3 回答
TA贡献1851条经验 获得超5个赞
值得记住的是,这Union是一种扩展方法。这是您正在调用的方法签名:
public static IEnumerable<TSource> Union<TSource> (
this IEnumerable<TSource> first,
IEnumerable<TSource> second);
所以你的电话是有效的:
var a = Enumerable.Union(list1, list2);
IEnumerable<BaseClass> b = Enumerable.Union(list1, list2);
var c = Enumerable.Union(list1.Cast<BaseClass>(), list2);
var d = Enumerable.Union(list1, list2.Cast<BaseClass>());
var e = Enumerable.Union(list1.Cast<BaseClass>(), list2.Cast<BaseClass>());
这些调用中涉及的参数类型是:
a: List<DerivedClass1>, List<DerivedClass2>
b: List<DerivedClass1>, List<DerivedClass2> // Variable being assigned to doesn't matter
c: IEnumerable<BaseClass>, List<DerivedClass2>
d: List<DerivedClass1>, IEnumerable<BaseClass>
e: IEnumerable<BaseClass>, IEnumerable<BaseClass>
这里显然分为三类:
a并且b是相同的。我们稍后再看。
c并且d是彼此的镜像。this请注意,就涉及类型推断而言,使用哪个作为参数并不重要。以后多...
e很简单:以非常明显的方式T推断BaseClass
现在a并且b不工作,因为BaseClass从不作为候选类型存在。根据我对类型推断算法的记忆(它确实非常复杂),当任何参数类型中都不存在该类型时,该类型将永远不会被推断为类型参数。因此,虽然BaseClass和object都是有效的显式泛型类型参数,但它们都不会被推断出来。
c并d决心T成为BaseClass,因为有推论要求从IEnumerable<BaseClass>to转换IEnumerable<T>,并且从List<DerivedClass2>or List<DerivedClass1>(分别为cand d) to 转换IEnumerable<T>。这仅适用于T=BaseClass所考虑的类型,所以这就是推断的。
TA贡献1852条经验 获得超7个赞
为什么编译器不能解析结果类型?
这个问题是基于错误的信念;编译器无法找出通用类型。编译器可以很容易地弄清楚这一点,它只是选择不这样做,这是有充分理由的。
当编译器对此进行推理时,它将始终使用表达式中涉及的类型。如果不是,那么它应该停在哪里?一切都可以简化IEnumerable<object>并使其工作,但这可能会掩盖意外行为并且可能是错误:
//ee is implicitly typed as IEnumerable<object>
var ee = someEnumerableOfString.Union(someEnumerableOfFoo);
操作员也会发生类似的事情?。编译器不会去寻找一个共同的祖先,无论是共同的基类型、接口还是简单的对象。
它是一个很好的功能,因为它并不总是清楚你想要什么共性。想象一下:
class A: IBar { }
class B: A, IFoo
class C: A, IFoo
var aa = someEnumerableOfB.Union(someEnumerableOfC);
为什么应该aa是 type IEnumerable<A>?为什么不IEnumerable<IFoo>呢?为什么不IEnumerable<IBar>呢?它可以永远持续下去......
在以下假设的法律声明中,另一个需要考虑的重要因素是,这可能会导致混淆:
IEnumerable<A> aa = someEnumerableOfB.Union(someEnumerableOfC);
有人可能会争辩说,您正在明确指定您想要与IEnumerable<A>.
但这不是编译器推断类型的方式;编译器不会尝试根据赋值左侧的类型信息来判断右侧的类型。它的工作方式是尝试找出右侧的类型,如果成功,那么它将查看其是否可分配给左侧。您得到的错误是因为它在第一步中失败了。
TA贡献1786条经验 获得超11个赞
它不能将 DerivedClass2 与 DerivedClass1 联合,它们共享一个基类,但无论如何它们都不是同一类型
var c = list1.Cast<BaseClass>().Union(list2); // This works
这将起作用,因为现在联合在 BaseClass 和 DerivedClass2 之间,并且 DerivedClass2 可以转换为 BaseClass,因为 baseClass.GetType().IsAssigneableFrom(derivedClass2)
- 3 回答
- 0 关注
- 134 浏览
添加回答
举报