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

时间:2011-11-12 15:19:18

标签: c# linq projection

是否可以使用Select to anonymous type进行投影?

以下是一些示例代码

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'

注意:如果我要定义一个实现ITest的类Test然后使用以下项目投影到该类中,我可以使上面的代码工作:

select   new Test {A = n.ToUpper(), B = 2012};

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

3 个答案:

答案 0 :(得分:5)

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

  

匿名类型是直接从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 );
 }

答案 1 :(得分:3)

您无法直接使用匿名对象执行此操作,但您可以使用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);
}

答案 2 :(得分:0)

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

你必须为此创建一个类。

一个选项可能是Duck Typing Project,它基本上在运行时生成一个包装类(因此会对性能和内存消耗造成损失)

(仅供参考,匿名类型是真实的,具体的类,由C#编译器生成.net运行时本身不支持它们.C#编译器不允许你修改它如何生成这些类。我没有试图看看Roslyn是否有帮助。)