2015-10-06 218 views
4

我在C#中的類型推斷中發現了一些奇怪的東西。C#類型推斷,泛型和接口

該示例。

我有一個接口

interface IInterface1 
{ 
} 

,並實現該接口

class Class1 : IInterface1 
{ 
} 

然後一類我有一個創建類

static Class1 GetInstanceOfClass1() 
{ 
    return new Class1(); 
} 

而且我要的功能使用泛型函數將返回一個可枚舉的

static IEnumerable<T> GetSomething<T>() where T : IInterface1 
{ 
    yield return GetInstanceOfClass1(); 
} 

完整的代碼

using System.Collections.Generic; 

namespace TypeInference 
{ 
    interface IInterface1 
    { 
    } 

    class Class1 : IInterface1 
    { 
    } 

    class Program 
    { 
     static Class1 GetInstanceOfClass1() 
     { 
      return new Class1(); 
     } 

     static IEnumerable<T> GetSomething<T>() where T : IInterface1 
     { 
      yield return GetInstanceOfClass1(); 
     } 

     static void Main(string[] args) 
     { 
     } 
    } 
} 

此代碼不編譯

無法隱式轉換類型 'TypeInference.Class1' 到 'T'

如果我寫as

yield return (T)GetInstanceOfClass1(); 

該錯誤消息是

無法將類型 'TypeInference.Class1' 到 'T'

它不能像以前那樣進行轉換。

好的。我寫的

yield return (IInterface1)GetInstanceOfClass1(); 

,並得到

無法隱式轉換類型 'TypeInference.IInterface1' 到 'T'

它不能像以前那樣轉換。

但如果我寫的

yield return (T)(IInterface1)GetInstanceOfClass1(); 

一切正常。

有人可以解釋我什麼是錯的,爲什麼代碼最終編譯?

謝謝。

+1

不保證'(T)(IInterface1)GetInstanceOfClass1();'不會在運行時中斷。可以創建'class NewClass1:IInterface1';調用'GetSomething ()'並得到異常。編譯器*信任你當你做類型轉換'(T)(IInterface1)',但運行時不會 – ASh

回答

8

這是爲了防止自己在腳下射擊。就像你設法最終做的一樣。

如果你定義

interface IInterface2 : IInterface1 { } 

,然後調用GetSomething<IInterface2>()會發生什麼?這是一個有效的泛型類型參數,但Class1不實現IInterface2

更糟糕的是,如果你定義

class Class2 : IInterface1 { } 

,然後發生了什麼叫GetSomething<Class2>()

你的設計被破壞了,你需要多思考一下,而不是繼續解決編譯錯誤,直到你有一個實際上有工作機會的設計。

3

您的類型參數T保證執行IInterface1,但它與Class1的關係未指定。

因此:

  1. Ť可能不是一個超類的Class1並且還Class1可能不是一個超類的T =>(T)GetInstanceOfClass1()失敗
  2. 不能返回來自方法的IInterface那返回T =>(IInterface1)GetInstanceOfClass1()失敗

的一個工程:

你當然可以投Class1IInterface,因爲Class1實現了接口。 既然T也實現了IInterface,它可能是一個有效的轉換,或者它可能會在運行時失敗。 這與在編譯時如何將任何對象轉換爲給定類型類似,但如果對象的運行時類型錯誤,則它在運行時會失敗。

E.g.

object o; 
o = 5; 
string s = (string)o; 

這是編譯,但在運行時失敗。