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

8

能否使用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'

注意:如果我定义了一个实现ITest接口的Test类,然后使用以下方式进行投影,就可以使以上代码正常工作:

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

为什么要这样做?我想看看是否可以仅定义接口而不必定义对象的具体实现,并让Linq为我创建对象。

1
为什么你想要一个 IQueryable 的结果而不是 IEnumerable 呢? - Arnaud F.
1
我正在尝试看看是否只能定义接口而不必定义具体实现,但是如果没有一些动态代码生成,这是不可能的。你必须有一个具体的对象。你要么有一个编译时具体类型,要么有一个运行时生成的类型。 - IAbstract
IQueryable是因为实际上我正在访问数据库。上面的代码只是一个例子。 - Raj Rao
3个回答

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 );
 }

你可以简单地引用该类的属性,而不需要接口。但这并不行,因为这个方法需要返回查询到的对象。(这是 DAL 的一部分,我在与一个数据库打交道,不是一个静态数组)。我只是想确定是否可以偷懒而不必创建这个类!你的回答很有道理 - 我不能这么做! - Raj Rao

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);
}

0

你不能这样做,因为匿名类型不实现接口。

你必须为此创建一个类。

一个选项可能是鸭子类型项目,它在运行时生成包装类(因此会对性能和内存消耗产生影响)

(仅供参考,匿名类型是由C#编译器生成的真正的具体类。.net Runtime本身不支持它们。C#编译器不允许您修改它如何生成这些类。我没有尝试看看Roslyn是否可以帮助解决这个问题。)


你也可以在运行时创建那个类。而且据我所知,当前的Roslyn版本是完全被动的。 - CodesInChaos
@CodeInChaos 非常正确,我刚刚添加了一个链接到“鸭子类型项目”,它正是这样做的。虽然开发人员可以使用运行时类生成来实现这一点,但我确实不建议对开发人员控制的类型使用它,但这确实是一种选择。 - Michael Stum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接