LINQ Union的不同类型 - 动态转换为接口?

时间:2012-11-24 11:41:29

标签: c# linq casting union

我有10个表作为不同类型呈现给LINQ,但共享完全相同的属性。当我尝试在它们上运行联合时,编译器告诉我:

"Argument 2: cannot convert from 'System.Collections.IEnumerable' to 'System.Collections.Generic.IEnumerable<LINQPad.User.TelJun2011>'"

代码看起来像这样

var jul = (from n in TelJul2011s select n);

var jun = (from p in TelJun2011s select p);

jun.Union(jul).Dump();

我已经完成了我的研究并理解不能在不同类型之间执行联合,我也理解,如果联合共享相同的属性,则可以对匿名类型执行联合。这个选项对我来说不起作用,因为我需要所有表中的所有属性,并且不希望必须输出相同的匿名类型10次 - 每个变量一次。我希望编译器根据所有属性相同的事实推断它们都是相同的类型。

我已经尝试使用AsQueryable()类型函数和“as”关键字转换为IEnumberable,Iqueryable,Datatable等。这些似乎都不适合我。

我想知道是否通过动态转换为父类型来实现此目的。我无法编辑类的初始声明,因此无法在它们上实现一个通用接口来强制转换。但是有一些方法可以在使用它们时将这些类型转换为通用接口,而无需编写从每种类型到父接口的转换吗?

感谢您的任何建议!

3 个答案:

答案 0 :(得分:8)

Union的结果将是IEnumerable<Xxx>,但在这种情况下,您必须指定Xxx是什么。如果类型TelJun2011TelJul2011 不是结构(值类型),您可以使用此IEnumerable<out T>协方差

jun.Union<object>(jul)

这是有效的,因为TelJun2011TelJul2011都是object,然后协方差IEnumerable<TelJun2011>IEnumerable<TelJul2011>都是IEnumerable<object>

当然object不具备TelJun2011TelJul2011共有的所有属性。如果这两种类型具有更有用的公共基类或实现一个通用接口会更好,因为那样你可以说例如:

jun.Union<ITelMonth>(jul)

其中ITelMonth是包含所需公共属性的某种类型。

答案 1 :(得分:0)

“问题”是C#的静态类型系统不允许你想要实现的目标。在将它们合并之前,您必须将对象强制转换为基类型。这意味着如果两者只有System.Object共同点,则必须将其转换为object或(对于.net 4.0)dynamic

后者将强制进行动态类型检查:

class A
{
    public int Integer { get; set; }
}

class B
{
    public int Integer { get; set; }
}

class Program
{
    public static void main(string[] args)
    {
        var a = new[] { new A { Integer = 5 }, new A { Integer = 6 }, new A { Integer = 7 } };
        var b = new[] { new B { Integer = 1 }, new B { Integer = 2 }, new B { Integer = 3 } };

        var u = a.Cast<dynamic>().Union(b).ToArray();

        var i1 = u[0].Integer;
        var i2 = u[1].Integer;
        var i3 = u[2].Integer;
        var i4 = u[3].Integer;
        var i5 = u[4].Integer;
        var i6 = u[5].Integer;
    }
}

在我看来,这不是一个理想的解决方案,但这可能对你有帮助。

答案 2 :(得分:0)

如果您正在使用EntityFramework(或任何其他框架,我猜),自动生成的类标记为partial,如下所示:

<强> /Project/Data/TelJun2011.cs

namespace Project.Data
{
    using System;
    using System.Collections.Generic;

    public partial class TelJun2011
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }
}

<强> /Project/Data/TelJul2011.cs

namespace Project.Data
{
    using System;
    using System.Collections.Generic;

    public partial class TelJul2011
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }
}

partial的含义是您可以为同一个类创建另一个文件。生成的类没有实现接口,但您可以轻松地实现自定义接口,如下所示:

<强> /Project/Data/ITelMonth.cs

namespace Project.Data
{
    public interface ITelMonth
    {
        int Id { get; set; }
        string Name { get; set; }
        string Description { get; set; }
    }
}

<强> /Project/Data/Partial/TelJun2011.cs

namespace Project.Data
{
    public partial class TelJun2011 : ITelMonth { }
}

<强> /Project/Data/Partial/TelJul2011.cs

namespace Project.Data
{
    public partial class TelJul2011 : ITelMonth { }
}

如果正确定义了接口,那么我们可以简单地执行此操作:

var jul = (from n in TelJul2011s select (ITelMonth)n);

var jun = (from p in TelJun2011s select (ITelMonth)p);

var bimester = jun.Union(jul);

你甚至可以访问像这样的公共属性:

foreach (var e in bimester)
{
    e.Id.Dump();
}