簡體   English   中英

避免在泛型方法中進行過多的類型檢查?

[英]Avoid excessive type-checking in generic methods?

我的問題涉及一系列通用方法中的類型檢查。 假設我有一個擴展方法,它嘗試將字節數組轉換為int,decimal,string或DateTime。

public static T Read<T>(this ByteContainer ba, int size, string format) where T : struct, IConvertible
{
    var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());            
    var magic = FromString<T>(s);
    return (T)Convert.ChangeType(magic, typeof(T));
}

這會調用一個名為FromString的方法,該方法將連接的字符串轉換為特定的類型。 不幸的是,業務邏輯完全依賴於類型T.所以我最終得到了一個巨石if-else塊:

private static T FromString<T>(string s) where T : struct
{
    if (typeof(T).Equals(typeof(decimal)))
    {
        var x = (decimal)System.Convert.ToInt32(s) / 100;
        return (T)Convert.ChangeType(x, typeof(T));
    }
    if (typeof(T).Equals(typeof(int)))
    {
        var x = System.Convert.ToInt32(s);
        return (T)Convert.ChangeType(x, typeof(T));
    }
    if (typeof(T).Equals(typeof(DateTime)))
        ... etc ...
 }

在這一點上,我更喜歡具有相同名稱和不同返回類型的多個方法,類似於以下內容:

// <WishfulThinking>
private static decimal FromString<T>(string s)
{
    return (decimal)System.Convert.ToInt32(s) / 100;
}    
private static int FromString<T>(string s)
{
    return System.Convert.ToInt32(s);
}
// </WishfulThinking>

...但我意識到這是無效的,因為T不能被約束到特定類型,沒有它,所有方法都將具有相同的沖突簽名。

有沒有一種可行的方法來實現FromString而沒有過多的類型檢查? 或者可能有更好的方法來解決這個問題?

或者可能有更好的方法來解決這個問題?

當然,有一個:你可以將每個轉換器變成一個lambda,制作它們的字典,並將它們用於轉換,如下所示:

private static IDictionary<Type,Func<string,object>> Converters = new Dictionary<Type,Func<string,object>> {
    {typeof(int), s => Convert.ChangeType(System.Convert.ToInt32(s), typeof(int))}
,   {typeof(decimal), s => Convert.ChangeType((decimal)System.Convert.ToInt32(s) / 100, typeof(decimal))}
,   ... // And so on
};
public static T Read<T>(this ByteContainer ba, int size, string format) where T : struct, IConvertible {
    Func<string,object> converter;
    if (!Converters.TryGetValue(typeof(T), out converter)) {
        throw new ArgumentException("Unsupported type: "+typeof(T));
    }
    var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
    return (T)converter(s);
}

通常,如果必須編寫必須始終檢查泛型類型參數類型的邏輯,那么實際上並不是編寫受益於泛型的代碼。 既然如此,假設您要解決的實際問題是需要將字節數組轉換為它所代表的某種可預測的內置類型,我建議您放棄這種方法並使用BitConverter類中的方法。

在您可以確定T的值的位置,只需在BitConverter類上調用適當的方法即可。

更新:如果需要通用解決方案,我建議類似於dasblinkenlight的答案,雖然我會讓調用者注入轉換器(畢竟,調用者知道必需的結果類型),這避免了維護轉換函數列表以及泛型方法:

public static T Read<T>(this ByteContainer ba, int size, string format, 
                        Func<string, T> converter) where T : struct, IConvertible 
{
    var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
    return converter(s);
}

暫無
暫無

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

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