2017-05-22 25 views
3

考慮下面的類:爲什麼泛型方法在通用方法不匹配時不能選擇特定方法?

public static class MWE 
{ 
    public static void Foo<T, TColl>(Expression<Func<IFoo, bool>> bar, TColl foos) 
     where TColl : IEnumerable<T> 
    { 
    } 

    public static void Foo<T, TColl>(Expression<Func<IFoo, T>> bar, TColl foos) 
     where TColl : IEnumerable<T> 
    { 
    } 

    static MWE() 
    { 
     Foo(bar => bar.GetThing(), new List<IThing>()); 
     Foo(bar => bar.GetBool(), new List<IThing>()); 
    } 
} 

public interface IFoo 
{ 
    IThing GetThing(); 

    bool GetBool(); 
} 

我得到的第二個呼叫編譯錯誤Foo,抱怨,有沒有轉換從List<IThing>IEnumerable<bool>。在我看來,編譯器沒有看到第一個重載,儘管它匹配(而第二個沒有)。

爲什麼?這兩種方法可以共存並且工作嗎?

+1

試着明確指出'Foo'的通用參數。類似於:'Foo >(bar => bar.GetBool(),new List ());'它不能正確推斷'T'應該是什麼。 –

回答

2

第一個重載不能被調用,因爲沒有足夠的信息來推斷泛型參數。您使用一個的通用參數,TColl,但您從未在簽名中使用T,因此無法推斷它。

如果您明確指定通用參數,那麼將選擇第一個重載並且將正常工作。

如果您完全刪除第二個通用參數,並在簽名中使用IEnumerable<T>而不是TColl,它將簡化這些方法並允許您的兩個現有調用正常工作。

+0

有趣。但是,當解析'TCollection'時,沒有足夠的信息來知道'T'是什麼嗎? –

+2

@TomasLycken沒有給出C#的泛型類型推斷如何工作。它不考慮通用約束。 – Servy

0

看這一個第一:

public static void Foo<T, TColl>(Expression<Func<IFoo, T>> bar, TColl foos) 
    where TColl : IEnumerable<T> 

編譯器如何弄清楚什麼T是什麼?它會查看通過它的表達式(bar)並查看返回類型是什麼。從中可以推斷出Tbar返回IThing,所以TIThingTCollIEnumerable<IThing>

現在看這一個:

public static void Foo<T, TColl>(Expression<Func<IFoo, bool>> bar, TColl foos) 
    where TColl : IEnumerable<T> 

什麼T?這不是bar返回的類型,它被硬編碼爲bool。那它是什麼?編譯器不能告訴,這樣你就可以使用這個功能的唯一方法是,如果你明確告訴它的泛型參數是:

Foo<IThing,List<IThing>>(bar => bar.GetBool(), new List<IThing>()); 

^這將編譯。

沒有能夠弄清楚什麼T是,它使用的第一個功能,推斷Tbool,然後它會抱怨,因爲你正在傳遞一個IEnumerable<IThing>時預計的IEnumerable<bool>

+0

我會問你同樣的後續行動,就像我在做@Servy一樣:爲什麼編譯器不能從集合中推斷出'T'(它必須實現'IEnumerable ')? –

+0

因爲這決定了'TColl'是什麼,而不是'T'是什麼。因爲'TColl'是'IEnumerable '而'TColl'是'IEnumerable ',所以'T'必須是'IThing',編譯器不會去推斷這個額外的步驟。你可以看到,遵循這樣的邏輯鏈可以讓你非常快速和清楚地丟失可怕的設計師認爲它不值得複雜。 –

2

泛型類型的限制(where ...)不用於泛型類型推斷(如果未明確說明,則推斷爲TTCall)。您可能會認爲您的第一次過載中的T類型可能會被推斷爲IThing,因爲您通過List<IThing>作爲TColl,但由於上述原因,情況並非如此。

由於不能推斷泛型類型 - 此方法不參與重載解析並使用第二種方法。這失敗了,你會看到編譯器錯誤。

+0

很好的解釋,謝謝! –