c# Linq将匿名类型投射到接口上

本文关键字:接口 类型 Linq | 更新日期: 2023-09-27 18:14:10

是否可以使用Select投射到匿名类型上?

下面是一些示例代码

public interface ITest
{
    string A{get;}
    int B{get;}
}
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IQueryable<ITest> query =
    from     n in names.AsQueryable()
    select   new {A = n.ToUpper(), B = 2012};

上面的代码导致

不能隐式转换类型"System.Linq"。IQueryable'到'System.Linq.IQueryable'

注意:如果我要定义一个实现ittest的类Test,然后使用: 将其投影到该类中,我可以使上面的代码工作。
select   new Test {A = n.ToUpper(), B = 2012};

为什么?我想看看我是否只能定义接口,而不必定义对象的具体实现,并让Linq为我创建对象

c# Linq将匿名类型投射到接口上

是的,您可以选择进入匿名类型,但是您不能既选择进入匿名类型,然后又像使用它们实现接口一样使用这些对象。原因是匿名类型不实现接口,即使它们在类型和名称上具有相同的属性。没有办法定义匿名类型实现接口。如果你想通过接口实现来使用对象,你必须选择一个实现该接口的具体类型。

匿名类型是直接从object派生的类类型,不能强制转换为object以外的任何类型。编译器为每个匿名类型提供一个名称,尽管您的应用程序无法访问它。从公共语言运行库的角度来看,匿名类型与任何其他引用类型没有什么不同。

裁判:http://msdn.microsoft.com/en-us/library/bb397696.aspx

我当然能理解你的意图。当类型是匿名的时候,如果编译器能直觉地知道类型符合接口定义,那就太好了,但这实际上只适用于接口严格由只读属性组成的情况。一旦接口用setter或方法定义了属性,匿名类型就不可能实现它了。另一方面,如果您按照预期使用匿名类型——作为特定用途的短期临时类型——您可以简单地引用它的属性,而根本不需要接口。
 var query = from     n in names.AsQueryable()
             select   new {A = n.ToUpper(), B = 2012};
 foreach (var item in query)
 {
      Console.WriteLine( item.A );
 }

您不能直接对匿名对象执行此操作,但是您可以使用Clay框架实现非常类似的功能:

public interface IPerson {
    string FirstName { get; set; }
    string LastName { get; set; }
}
public static void CastToCLRInterface() {
    dynamic New = new ClayFactory();
    var person = New.Person();
    person.FirstName = "Louis";
    person.LastName = "Dejardin";
    // Concrete interface implementation gets magically created!
    IPerson lou = person;
    // You get intellisense and compile time check here
    Console.WriteLine("{0} {1}", lou.FirstName, lou.LastName);
}

不能,因为匿名类型不实现接口。

你必须为此创建一个类。

一个选项可能是Duck Typing Project,它本质上是在运行时生成一个包装器类(因此带来性能和内存消耗的损失)

(仅供参考,匿名类型是真实的,具体的类,由c#编译器生成。.net运行时本身不支持它们。c#编译器不允许你修改它生成这些类的方式。我还没有试着看看Roslyn能否帮上忙。