【问题标题】:Casting Linq Query Results to an Interface将 Linq 查询结果转换为接口
【发布时间】:2012-12-12 03:44:45
【问题描述】:

我正在尝试编写一个将结果转换为接口的 Linq (to Objects) 查询,如下所示:

    var data = (from row in CicApplication.Vaporizer473Cache
                where row.Coater == coater
                select row).Cast<IVaporizerData>();

这似乎是唯一的方法,因为我无法在选择中创建接口的实例。我有两个问题:

  1. 演员实际上是如何完成的?它会在源中找到每个属性,并将其值复制到同名的接口属性中吗?

  2. 我的界面中有一个不包含在源代码中的属性,但我想在此操作期间以某种方式设置它的值。这可能吗?还是我需要在查询之后,在每个语句中执行它?

如果有帮助,数据源 (Vaporizer473Cache) 的类定义如下所示。界面非常相似。

internal class Vaporizer473
{
    /// <summary>
    /// Gets or sets the Coater property
    /// </summary>
    public string Coater { get; set; }

    /// <summary>
    /// Gets or sets the CoaterTime property
    /// </summary>
    public DateTime? CoaterTime { get; set; }

    /// <summary>
    /// Gets or sets the TemperatureLeftTubeA property
    /// </summary>
    public double? TemperatureLeftTubeA { get; set; }

    /// <summary>
    /// Gets or sets the TemperatureLeftTubeB property
    /// </summary>
    public double? TemperatureLeftTubeB { get; set; }

    /// <summary>
    /// Gets or sets the TemperatureRightTubeA property
    /// </summary>
    public double? TemperatureRightTubeA { get; set; }

    /// <summary>
    /// Gets or sets the TemperatureRightTubeB property
    /// </summary>
    public double? TemperatureRightTubeB { get; set; }

}

【问题讨论】:

  • 否;这只会抛出一个InvalidCastException

标签: c# linq interface


【解决方案1】:

即使编译器不会抱怨您提供的语法,它也不会运行。您不能将对象强制转换为它未实现的接口。

Cast 方法只是一种方便的方法,它尝试将给定IEnumerable 中的每个对象转换为您提供的泛型类型。如果 Vaporizer473 确实 实现了IVaporizerData,那么你可以简单地说:

var data = from row in CicApplication.Vaporizer473Cache
           where row.Coater == coater
           select (IVaporizerData)row;

其次:

我的界面中有一个不包含在源代码中的属性,但我想在此操作期间以某种方式设置它的值。这可能吗?还是我需要在查询之后,在每个语句中执行它?

正如您现在所知道的,您的类必须在您的接口中实现该属性。 (您可以这样做explicitly,这样它就不会在您的实际类实现等上挤满智能感知。)使用复杂的Select 委托来设置值是可能,但是这不是 LINQ 的用途,我极力劝阻它。在这种情况下,for 循环是合适的做法。

请记住,如果您修改来自缓存的项目,您将修改原始对象而不是它们的克隆。这可能会产生深远的影响。您可能希望创建新对象来表示您正在寻找的数据。

【讨论】:

  • 好的。所以如果我理解正确的话,我的 Vaporizer473 类需要实现 IVaporizerData?
  • @RandyMinder:没错。如果您希望能够对该接口进行强制转换,那么它必须实现该接口。
【解决方案2】:
  1. 非常简单。 铸造一个对象到另一个类型并不意味着另一个对象被创建。对同一对象的不同“视图”很简单。你的类必须实现接口才能做到这一点。所以强制转换意味着相同的对象仍然在可枚举中。

  2. 由于你在转换对象时没有创建新对象,因此无法设置接口的额外属性的值。但这也意味着您的对象中已经拥有该属性,因为您的对象正在实现接口。

【讨论】:

    【解决方案3】:

    要回答您的第一个问题,是的,就是这样做的。但是,查看您的代码,似乎Vaporizer473 类没有实现IVaporizorData。假设这只是一个疏忽?如果没有,您需要实现该接口才能使Cast&lt;&gt;() 调用起作用。

    至于您的第二个问题,是的,您可以在之后将其设置在一个 for-each 块中,或者您可以使用 Select 来设置属性并进行强制转换,如下所示:

    CicApplication.Vaporizer473Cache
    .Where( r => r.Coater = coater)
    .Select((r) => {
       r.SomeProperty = somevalue;
       return r as IVaporizerData
    });
    

    【讨论】:

    • 是的,似乎是疏忽。谢谢。
    猜你喜欢
    • 2012-07-05
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    • 2013-02-24
    相关资源
    最近更新 更多