2010-12-15 74 views
2

我正在寫一個簡單的概念證明,應該是什麼,實質上是一個解析器生成器。你可以返回一個基於泛型類型的函數嗎?

基本上我正在尋找我能寫會返回一個字符串轉換爲給定類型的一些物體的功能的函數的方式 - 我希望能夠做到在本質上是以下幾點:

Func<string, double> ConvertToDouble = BuildConverter(typeof(0.0)); 

很明顯,這是一個非常人爲的例子 - 但如果我可以做簡單的版本,那麼我應該可以做更復雜的版本!我最終試圖做的是將一個值的字符串映射到一個類,但爲了使它儘可能靈活,我想通過一個函數返回一個函數來做到這一點轉換。在功能方面,我覺得我想要的東西,看起來像這樣:

a -> (string -> a) 

作爲第一次嘗試,我試着這樣做:

public static Func<string, T> BuildParser<T>(T t) 
    { 
     if (t is String) 
     return new Func<string, T>(x => x.ToString()); 
     if (t is double) 
     return new Func<string, T>(x => double.Parse(x)); 
    } 

這並不在所有的工作,但它讓我感覺有點卡住,我應該採取什麼方法 - 所以任何幫助都將不勝感激!

+3

你似乎缺少泛型的點,如果你在你的通用功能尋找_types_。 – Oded 2010-12-15 17:17:40

+2

如果您想要運行時決策,那麼您不應該使用泛型。如果你想編譯時決定,那麼你不應該使用「是」。 – 2010-12-15 17:18:20

+0

@Oded - 我不確定我是否同意,我只是在尋找特定類型的多態。 – MrBear 2010-12-16 13:00:34

回答

0

你不能struct類型混合class。除此之外,它會起作用。

請參見下面的代碼:

private void Testing() { 
    var func = BuildParserStruct<double>(); 
    double value = func("5"); 
} 

public static Func<string, T> BuildParserClass<T>() where T : class 
{ 
    return x => x as T; 
} 

public static Func<string, T> BuildParserStruct<T>() where T : struct 
{ 
    return (x => (T)Convert.ChangeType(x, typeof(double))); 
} 
+0

看起來很有趣!我會試一試 - 我完全忘了'where T:'語法。 – MrBear 2010-12-16 09:17:42

+0

是什麼讓你覺得你不能「將'class'與'struct'類型混合?這可以通過一個'BuildParser '方法完成;如果你不想要,你不需要單獨的'BuildParserClass '和'BuildParserStruct '方法。 (以我的答案爲例) – LukeH 2010-12-20 00:55:43

+0

夠公平的。我應該說的是,泛型方法不能在不使用反射的情況下實例化結構和類類型(或派生類型)。這個限制不影響你的解決方案,因爲你的泛型方法沒有實例化任何東西......我發現你的解決方案很聰明,即使有限(在處理30種不同的類型時需要30個項目的緩存,等等)... – rsenna 2010-12-27 18:35:41

0

我猜你想在編譯時驗證特定的行爲。爲什麼不直接撥打Convert或編寫單獨的方法來使用?如果您的陳述完成了所有的事情,那麼程序員應該選擇恰當的轉換方法。

如果您想要在運行時選擇行爲,則應返回Func<string, object>,並使該方法非泛型。

在該方法中使用泛型類型T的問題在於,對於每次調用該方法的T都是固定的,並且該方法中的邏輯假設T在一次調用中變化(在一種情況下,T是一個字符串,在另一種情況下,T是十進制)。編譯器無法對此進行排序 - 它需要允許可返回的實例具有相同的類型。

+0

就我的例子而言,你是正確的 - 它只是一個概念證明。最終,我有一個消息系統,以逗號分隔的字符串發送消息,每個消息都可以映射到一個類(或一個結構體)。這意味着只要有人在這裏使用該消息系統編寫應用程序,他們就需要手動編寫他們如何將其映射到課程的代碼。本質上,我想要做的是通過編寫一個映射器生成器來實現自動化。 – MrBear 2010-12-16 07:57:51

0

我不確定你想要做什麼,但會有這樣的幫助嗎?

var stringParser = GetParser<string>(); 
string s = stringParser("test"); 

var doubleParser = GetParser<double>(); 
double d = doubleParser("42"); 

// ... 

public static Func<string, T> GetParser<T>() 
{ 
    return (Func<string, T>)_parserCache[typeof(T)]; 
} 

private static readonly Dictionary<Type, Delegate> _parserCache = 
    new Dictionary<Type, Delegate> 
     { 
      { typeof(string), new Func<string, string>(x => x) }, 
      { typeof(double), new Func<string, double>(x => double.Parse(x)) } 
      // etc 
     }; 
0

ADO.Net有一個執行標量函數,一直困擾着我,因爲它返回一個對象。你可以編寫一個通用包裝函數來返回適當的類型。當然這假定你知道什麼類型將被返回。

有些簡化:

public T ExecuteScalar<T>() 
    { 
     return (T)Command.ExecuteScalar(); 
    } 
相關問題