为什么在这种情况下不能进行类型推断?

时间:2019-08-27 11:24:29

标签: c#

假设我有一个POCO和一个List类:

class MyClass
{...}

class MyClasses : List<MyClass> 
{...}

以及以下将IEnumerable<MyClass>映射到MyClasses列表的方法:

public static TListType ToListOfType<TListType, TItemType>(this IEnumerable<TItemType> list) where TListType : IList<TItemType>, new()
{
    var ret = new TListType();

    foreach (var item in list)
    {
        ret.Add(item);
    }

    return ret;
}

我希望这段代码能够编译,但是不会:

var list = someListOfMyClass.ToListOfType<MyClasses>();

但是我得到

  

错误CS1061'IEnumerable'不包含以下定义   'ToListOfType',并且没有可访问的扩展方法'ToListOfType'   接受类型为“ IEnumerable”的第一个参数可能是   找到(您是否缺少using指令或程序集引用?)

但是,这确实可行:

var list = someListOfMyClass.ToListOfType<MyClasses, MyClass>();

我不明白为什么类型推断不足以使编译器知道项的类型,因为this变量是已知类型的列表。

2 个答案:

答案 0 :(得分:5)

类型推断不会从通用方法调用中推断 missing 参数。相反,它可以推断 all none 个参数。因此,您不能使用一个类型参数来调用该方法,而期望编译器提供其余的参数。

在这种情况下,可以推断TItemType,因为它在参数之一中。 TListType不能被推断,因为它是返回类型。因此,最后无法推断出方法签名,而您必须指定所有类型参数。

答案 1 :(得分:2)

正如其他人所说,c#不支持部分泛型类型参数推断。

关于为什么不能推断出其中一种类型的原因,也许有一个更明显的例子更清楚了:

TPeeledFruit peeled = Peel<TPeeledFruit, TFruit)(
    this TFruit fruit) where TPeeledFruit: TFruit

好的,现在你说:

var myPeeledBanana = Peel(myBanana)

编译器很容易推断出TFruit必须为Banana

但是如何推断TPeeledFruit是什么呢?它没有任何类型的信息。您可能会认为它很明显,因为您了解这种关系,但是编译器却没有这种知识。它唯一知道的是TPeeledFruit必须是从TFruit继承的类型,但可以是无限数量的类型:它可以再次为Banana,可以是{{1} },可以是PeeledBananaPeeledRipeBanana

还要考虑这样一个事实,即明确地键入分配对任何情况都没有帮助:

PeeledGreenBanana

这也不起作用,因为c#会先在赋值的右侧键入类型,然后计算出赋值实际上是否合法。如果它是隐式类型的变量,则赋值始终有效。