2010-01-08 39 views
1

我有一個泛型類,我需要約束只值類型(int,float等)。我有一個基於類型測試調用Parse方法的方法。例如:演員值類型到通用

class MyClass<T> 
{ 
    ... 

    private static T ParseEntry(string entry) 
    { 
     if(typeof(T) == typeof(float)) 
     { 
      return (T) float.Parse(entry); 
     } 

     if(typeof(T) == typeof(int)) 
     { 
      .... you get the idea 
     } 
    } 
} 

約束噸至struct不工作,我真的想避免裝箱/如果可能的話拆箱。有任何想法嗎?

編輯:多給點見識。我注意到在一個庫中,我正在開發兩個類具有非常相似的屬性/方法等,唯一的區別是數據的基礎類型(int或float)。這引導我進行泛型設計。唯一的困擾是因爲調用特定的Parse方法,這取決於它是float還是int。我可以用拳擊/拆箱來解決它,但如果可能的話,我真的很想避免這種情況。

回答

4

不幸的是,你不能創建描述類型的約束。你可以不寫,例如:

class MyClass<T> where T : int { ... } // won't compile 

你可能會更好離開約束爲struct,但增加了一些運行時檢查,以確保T是隻有當你實例化的類支持的類型之一。由於你沒有多說你計劃如何使用你的班級 - 很難提供關於如何實現更好的類型安全的替代設計建議。

編輯:你應該看看Marc和其他人推薦的類型轉換器選項。這似乎是要走的路。

編輯:發生在我一個可能的想法,就是讓Parse()方法實際上是一種委託:Func<string,T> - 你施工期間分配。這將使您可以:

  1. 避免低效率和尷尬if/else邏輯。
  2. 提高未來使用你的類到其他值類型(結構不同,BigDecimal等)

這裏是什麼,我的意思是一個代碼示例:

class MyClass<T> 
{ 
    private readonly Func<string,T> ParseEntry; 

    public MyClass(Func<string,T> parser)  
    { 
     ParseEntry = parser; 
    } 
} 

public static class AvailableParsers 
{ 
    public static Func<string,int> ParseInt = s => int.Parse(s); 
    public static Func<string,float> ParseFloat = s => float.Parse(s); 
} 

您可以閱讀有關available constraints here。唯一可用的約束條件是:

  • 結構(可選)
  • 新()(可選)
  • 接口約束(可選,多個允許)
  • 基類約束(可選,只允許一個)
  • 赤裸裸的限制(如其中T:TResult)
+0

現在我想知道...... CLR是否允許'System.Int32'作爲約束?我們可以用Jon Skeet在Unconstrained Melody上使用的相同技巧嗎? –

+0

@Martinho:不,你不能。那又有什麼意義呢?像MyFunc (T num)這樣的方法簽名,其中T:int將與「MyFunc(int num)」實際上相同。 – LukeH

+0

代表解決方案似乎是最簡單的。構造函數在庫的內部(即用戶可以訪問創建的對象,但不能創建它們),因此傳遞額外的參數沒有什麼大不了的。 –

4

愚蠢的可能,但 - 如果你談論的是一組有限的類型,你爲什麼不只是超載的方法?像*Writer.Write()方法一樣,每個「基」類型都有重載?

簡而言之:爲什麼是通用的,如果你根據類型做了不同的事情(不知何故,這種做法無論對於傳入的任何類型都會做同樣的事情)。我想你可能真的想用Convert.ChangeType

事情是這樣的:

class MyClass<T> where T: IConvertible 
{ 
    private static T ParseEntry(string entry) 
    { 
     return (T)Convert.ChangeType(entry, typeof(T)); 
    } 
} 
0

像Bushkin先生說,你不能這樣做。所以你另外的選擇是簡單地爲每個基本類型做一些方法的重載。另外,假設你不必處理原始類型,但你真的想要處理所有的結構 - 它仍然是不可能的,因爲結構不能保證實現一個(迄今爲止虛構的)接口所謂的IParsable被鑄成T.

1

我想我在這裏看不到數值...爲什麼不使用Convert類?

11
private static T ParseEntry(string entry) 
{ 
    TypeConverter conv = TypeDescriptor.GetConverter(typeof(T)); 
    return (T) conv.ConvertFromString(entry); 
} 

它的優點是可以與任何類型的轉換器一起工作(或者您可以在運行時自行添加)。它確實有拳擊,但真的,it isn't so bad。如果這是你最大的問題,那麼你會以錯誤的方式去做。

+0

我運行上面的代碼,而不是隻調用Parse方法,我發現它慢了5倍。不知道是否會同意Skeet的博客,拳擊是「在噪音」。我同意你不應該跳過設計籃圈來避免它,但如果可能的話應該避免。 –

+0

正是我在找的東西。謝謝@Marc Gravel。 – JCallico