3

我有 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 等。这些对我来说似乎都不起作用。

我想知道是否有某种方法可以通过动态转换为父类型来做到这一点。我不能编辑类的初始声明,所以不能在它们上实现一个通用接口来转换。但是有什么方法可以在使用时将类型转换为通用接口,而无需编写从每种类型到父接口的转换?

感谢您的任何建议!

4

3 回答 3

9

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

jun.Union<object>(jul)

This works because TelJun2011 and TelJul2011 are both object, and then by covariance IEnumerable<TelJun2011> and IEnumerable<TelJul2011> are both IEnumerable<object>.

Of course object does not possess all the properties common to TelJun2011 and TelJul2011. It would be better if these two types had a more useful common base class or implemened a common interface, because then you could say e.g.:

jun.Union<ITelMonth>(jul)

where ITelMonth were some type containing the common properties you want.

于 2012-11-24T13:13:21.943 回答
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;
    }
}

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

于 2012-11-24T11:57:01.820 回答
0

If you're using EntityFramework (or any other framework, I guess), the classes auto-generated are marked as partial, such as the following:

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

What partial means is that you can create another file for the same class. The generated classes don't implement an interface, but you can easily make then implement your custom interface like this:

/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 { }
}

And having correctly defined the interfaces, then we can simply do this:

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

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

var bimester = jun.Union(jul);

And you can even access the common properties like such:

foreach (var e in bimester)
{
    e.Id.Dump();
}
于 2015-01-02T22:54:37.223 回答