簡體   English   中英

泛型參數T不能隱式分配給對象-泛型方法調用非泛型重載方法

[英]Generic parameter T not implicitly assignable to object — generic method calling nongeneric overloaded method

考慮到object是C#最終基類,為什么System.Collections.Generic.IEnumerable<T>不能分配給參數類型System.Collections.Generic.IEnumerable<object>


當執行類似於以下代碼的操作時,我偶然發現了這種好奇心。 這是一個泛型方法,稱為重載非泛型方法。

void Main()
{
    List<object> objects = new List<object>();

    Method(objects); // This calls the method with IEnumerable, as expected

    MethodCaller(objects); 
}

void MethodCaller<T> (IEnumerable<T> objects) 
{
    Method(objects); // Calls method overload 2, with object as parameter - why?

    // Why is the following line required to call the method overload 1? 
    // Can't C# do this automatically, given that object is the ultimate base class for everything?
    IEnumerable<object> casted = (IEnumerable<object>) objects; 
    Method(casted); // Calls method overload 1
}

void Method (IEnumerable<object> param) 
{
    // Method overload 1
    Console.WriteLine("Method overload 1 - with IEnumerable<object> as parameter");
}

void Method (object param) 
{
    // Method overload 2
    Console.WriteLine("Method overload 2 - with object as parameter");
}

我不明白為什么通用方法不應調用第一個重載而不是第二個重載。 我認為編譯器應該能夠說任何<T>都可以隱式轉換為object ,因此IEnumerable<T>應該可以隱式轉換為IEnumerable<object>

換一種說法:

IEnumerable<object> casted = (IEnumerable<object>) objects; 

為什么要求此行調用方法重載1? 鑒於對象是最終的基類,C#不能自動執行此操作嗎?

是因為C#假定我可能會傳遞與類型object不兼容的<T> -即使實際上所有object都是object

讓我們在這里從方程式中排除過載解決方案。 這是關於一般差異 特別是,您期望從IEnumerable<T>IEnumerable<object>進行隱式轉換。

那是行不通的,因為通用方差僅在已知類型實參為引用類型時才起作用。 從鏈接的文檔中:

方差僅適用於引用類型; 如果為變量類型參數指定值類型,則該類型參數對於生成的構造類型而言是不變的。

因此,例如,這很好:

IEnumerable<string> strings = ...;
IEnumerable<object> objects = strings;

但這失敗了:

IEnumerable<int> ints = ...;
IEnumerable<object> objects = ints;

在您的一般情況下, T可以是任何類型, 包括value類型 這就是為什么它失敗了。 如果你限制T為引用類型,使用where T : class約束,它的罰款。

因此,具體來說,這是無效的:

static void Foo<T>(IEnumerable<T> ts)
{
    IEnumerable<object> objects = ts;
}

但這是有效的:

static void Foo<T>(IEnumerable<T> ts) where T : class
{
    IEnumerable<object> objects = ts;
}

IEnumerable <object>不是IEnumerable <T>的超類(無論T是什么)。 您不能將第二個分配給第一種類型的變量,因為它們被認為是完全不同的。 您需要將IEnumerable的類型轉換為對象,然后才能獲得匹配的簽名,例如:

void MethodCaller<T> (IEnumerable<T> objects) 
{
    Method(objects.Cast<object>()); 
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM