2011-11-17 36 views
58

我可以打電話Get<int>(Stat);Get<string>(Name);無法隱式轉換類型「詮釋」到「T」

但是當編譯我得到:

無法隱式轉換類型「詮釋」到「T」

string相同的東西。

public T Get<T>(Stats type) where T : IConvertible 
{ 
    if (typeof(T) == typeof(int)) 
    { 
     int t = Convert.ToInt16(PlayerStats[type]); 
     return t; 
    } 
    if (typeof(T) == typeof(string)) 
    { 
     string t = PlayerStats[type].ToString(); 
     return t; 
    } 
} 
+4

您可能認爲if語句檢查到T是int,因此在該語句塊中,您知道T是int,並且您應該能夠將int隱式轉換爲T.但是,編譯器並非設計爲遵循該推理,它只知道通常T不是從int派生的,因此它不允許隱式轉換。 (如果編譯器支持它,驗證者不會,因此編譯後的程序集將無法驗證。) – JGWeissman

回答

99

無論何時您發現自己在通用的中打開某個類型,您幾乎肯定會做出錯誤。泛型應該是generic;它們應該完全獨立於的類型操作

如果T只能是int或字符串,那麼不要以這種方式編寫代碼。 編寫兩個方法,一個返回一個int,另一個返回一個字符串。

+2

你能否詳細說明何時會出錯? –

+1

獲取汽車執行IConvertible將導致破損。當有人看到你有一個通用的方法時,他們會認爲他們可以通過實現IConvertible的任何事情。 – Tjaart

+5

我只能部分地同意你,@Eric。我有一種情況,我必須解析存儲在XML標籤中的數組。問題是XML文檔遵循的規範(在我的案例中是COLLADA)說這樣的數組可以不僅僅是float,int和bool,還有一些自定義類型。但是,如果你得到一個float [](array-tags包含名稱中存儲數據的類型:float_array存儲浮點數),則需要將字符串解析爲一個數組這需要使用一些IFormatProvider)。我顯然不能使用「T.Parse(...)」。因此,對於一小部分情況,我需要使用這種切換。 – rbaleksandar

9
public T Get<T>(Stats type) where T : IConvertible 
{ 
    if (typeof(T) == typeof(int)) 
    { 
     int t = Convert.ToInt16(PlayerStats[type]); 
     return t as T; 
    } 
    if (typeof(T) == typeof(string)) 
    { 
     string t = PlayerStats[type].ToString(); 
     return t as T; 
    } 
} 
+2

'return(T)t;'因爲不需要空值檢查。 – BoltClock

+1

如果條件檢查no null –

+0

哈! +1:我有一個不同的問題,但T的回報爲我解決了它。謝謝。 – CodeChops

95

你應該能夠只使用Convert.ChangeType(),而不是您的自定義代碼:

public T Get<T>(Stats type) where T : IConvertible 
{ 
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T)); 
} 
+2

謝謝,完美的作品 –

+7

'return(T)(object)PlayerStats [type];' – maxp

+0

謝謝你提供的答案。永不說永不」。 – mikesigs

6

ChangeType可能是您最好的選擇。我的解決方案與BrokenGlass提供的一些try catch邏輯類似。

static void Main(string[] args) 
{ 
    object number = "1"; 
    bool hasConverted; 
    var convertedValue = DoConvert<int>(number, out hasConverted); 

    Console.WriteLine(hasConverted); 
    Console.WriteLine(convertedValue); 
} 

public static TConvertType DoConvert<TConvertType>(object convertValue, out bool hasConverted) 
{ 
    hasConverted = false; 
    var converted = default(TConvertType); 
    try 
    { 
     converted = (TConvertType) 
      Convert.ChangeType(convertValue, typeof(TConvertType)); 
     hasConverted = true; 
    } 
    catch (InvalidCastException) 
    { 
    } 
    catch (ArgumentNullException) 
    { 
    } 
    catch (FormatException) 
    { 
    } 
    catch (OverflowException) 
    { 
    } 

    return converted; 
} 
4

考慮@BrokenGlass邏輯(Convert.ChangeType)不支持GUID類型。

public T Get<T>(Stats type) where T : IConvertible 
{ 
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T)); 
} 

錯誤:從 'System.String' 到 '的System.Guid' 無效的演員。

取而代之,使用下面的邏輯使用TypeDescriptor.GetConverter加入System.ComponentModel命名空間。

public T Get<T>(Stats type) where T : IConvertible 
{ 
    (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type]) 
} 

閱讀this

5

試試這個:

public T Get<T>(Stats type) where T : IConvertible 
{ 
    if (typeof(T) == typeof(int)) 
    { 
     return (T)(object)Convert.ToInt16(PlayerStats[type]); 

    } 
    if (typeof(T) == typeof(string)) 
    { 

     return (T)(object)PlayerStats[type]; 
    } 
} 
+0

謝謝你的幫助,我的需求是不同的。我正在爲現有的靜態方法編寫一個模擬方法,以便我可以對其進行測試。使用此http://osherove.com/blog/2012/7/8/faking-static-methods-in-moq-fakeiteasy-and-nsubstitute-migh.html – Esen

0

其實,你可以將其轉換爲object,然後T

T var = (T)(object)42;

一個例子爲bool

public class Program 
{ 
    public static T Foo<T>() 
    { 
     if(typeof(T) == typeof(bool)) { 
      return (T)(object)true; 
     } 

     return default(T); 
    } 

    public static void Main() 
    { 
     bool boolValue = Foo<bool>(); // == true 
     string stringValue = Foo<string>(); // == null 
    } 
} 

有時,這種行爲是可取的。例如,在從基類或接口實現或覆蓋通用方法時,您想要添加基於T類型的一些不同功能。

相關問題