关于c#:需要在Union()中通过匿名类型显式转换

Need to cast explicitly thru anonymous type in Union()

我有两个var/对象,通过这两个函数检索:

1
2
3
4
private IQueryable<Project> SelectAll_1(...)
{
    return query;
}

类项目是:

1
2
3
4
private int ID;
private string col1;
private string col2;
private string col3;

另一个:

1
2
3
4
private IQueryable<Project_test> SelectAll_2(...)
{
    return query;
}

其中poco of是:

1
2
3
4
private string ID_inString;
private string col1;
private string col2;
private string col3;

我需要对他们两个执行联合,

1
2
3
4
var P2 = SelectAll_2(...);
var P1 = SelectAll_1(...);

var P3 = P2.Union(P1);

但我得到了一个错误,提到:

The type arguments for method 'System.Linq.Queryable.Union(System.Linq.IQueryable, System.Linq.Expressions.Expression>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

我看到一些人通过匿名类型来解决这个问题,但我不知道它是如何工作的。有人知道吗?


你不能合并两种不同的类型,除非其中一种继承自另一种(例如,你可能会找到IEnumerableIEnumerable的联合,尽管这很少有用)。

现在在您的例子中,如果不同的属性具有相同的含义,那么听起来ProjectProject_test应该是一种类型。目前,ID属性有不同的类型——但这真的是必要的还是可取的?如果它们都是具有相同作用域的标识符,那么将它们存储在相同的表示中是有意义的。如果属性没有相同的含义,就不应该在它们之间形成联合。如果它们有相同的含义,您应该尝试使两个序列使用相同的类型。

您可以为此使用匿名类型,方法如下:

1
2
3
4
var projectedP1 = P1.Select(x => new { x.ID, x.col1, x.col2, x.col3 });
var projectedP2 = P2.Select(x => new { ID = int.Parse(x.ID_inString),
                                            x.col1, x.col2, x.col3 });
var union = projectedP1.Union(projectedP2);

或者您可以只使用现有类型之一:

1
2
3
4
5
6
var projectedP1 = P1.Select(x => new Project_test {
                                     ID_inString = x.ID.ToString(),
                                     col1 = x.col1,
                                     col2 = x.col2,
                                     col3 = x.col3 });
var union = projectedP1.Union(P2);

这并不是很明显哪一个是更好的主意,但如果可能的话,我会继续尝试调和这两种类型,在这一点上,你没有任何问题。


问题是,P2IQueryable,而P3IQueryable,由于它们的类型不同,所以不能将它们合并成一个序列。

你需要做的是用一个Select()调用将它们都投影到一个公共类型中,据我所知,该调用必须是一个命名类型,根据jon skeet,它可以用一个匿名类型来完成。定义匿名类型的初始化块必须具有相同数量的成员、相同的名称、相同的顺序、相同的类型才能被视为一种类型。要使用Select()投影类型,还需要使属性成为公共的,以便可以访问linq方法。