2012-02-18 91 views
5

可能重複:
C# generic constraint for only integers如何在C#中總結泛型數字?

正如你可以在下面的代碼中看到的,我需要計算兩個通用數字的總和。

public class NumberContainer<T> 
{ 
    public T ValueA { get; private set; } 
    public T ValueB { get; private set; } 
    public T Total { get { return ValueA + ValueB; } } 
} 

然而,這是不可能做直接加入兩個T的值,這導致編譯器錯誤下面:

運算符「+」不能被應用於類型的操作數'T'和'T'

鑑於我不打算使用T來表示數字(short,ushort,int,uint等)的值類型以外的任何東西,我怎樣才能執行和? (效率是一個需要考慮的因素)

+0

或可能實施的具體類:是否有一個C#泛型約束爲「實數」類型?](http://stackoverflow.com/questions/1348594/is-there-ac-sharp-generic-constraint-for-real-number-types/1348625#1348625) – 2012-02-18 04:05:21

+1

該問題是關閉作爲問題的副本試圖對'T'施加約束,這是*這個問題試圖去做的。我認爲它應該重新開放。 – dasblinkenlight 2012-02-19 03:50:56

回答

12

您可以用LINQ「小魔術」做到這一點:

private static readonly Func<T, T, T> adder; 
static NumberContainer() { 
    var p1 = Expression.Parameter(typeof (T)); 
    var p2 = Expression.Parameter(typeof (T)); 
    adder = (Func<T, T, T>)Expression 
     .Lambda(Expression.Add(p1, p2), p1, p2) 
     .Compile(); 
} 
public T Total { get { return adder(ValueA, ValueB); } } 

唯一的缺點是,這種代碼編譯即使NumberContainer與一類T不支持除了實例化;當然它會在運行時拋出異常。另外一個好處是,這個應該與用戶定義的+操作符一起使用。

1

您可以爲T指定一個約束條件,它必須是一個結構體,也許它實現了IConvertable,然後使用Convert

public class NumberContainer<T> 
     where T : struct, IConvertible 
    { 
     public T ValueA { get; private set; } 
     public T ValueB { get; private set; } 
     public T Total { 
      get 
      { 
       // do type checking here, then: 

       return (T)Convert.ChangeType(
        Convert.ToDouble((object)ValueA) + 
        Convert.ToDouble((object)ValueB), typeof(T)); 
      } 
     } 
    } 

但是,在編譯時,泛型沒有辦法保證T是整數或浮點類型。但是,您可以在運行時檢查它,並拋出異常。

+0

這也行不通。事實上,你的建議甚至沒有編譯。 – 2012-02-18 04:09:51

+0

把它從我的頭頂上掉了下來,修正並編譯。如果您想進一步闡述爲什麼它不起作用,那會更有幫助。 – HackedByChinese 2012-02-18 04:19:43

+0

DateTime是一個struct和一個IConvertible,但不能轉換爲double,所以只要用DateTime參數調用它,就會拋出一個異常。 – 2016-05-09 10:45:51

5

除了使用LINQ,如果你是在.NET 4,這是可能的使用dynamic

static T Add<T>(T x, T y) 
{ 
    dynamic dx = x, dy = y; 
    return dx + dy; 
} 

在您的代碼示例這個變成:

public class NumberContainer<T> where T: struct 
{ 
    public T ValueA { get; private set; } 
    public T ValueB { get; private set; } 
    public T Total { get { return ((dynamic)ValueA) + ((dynamic)ValueB); } } 
} 

這種方法沒有按」儘管如此,確保安全。如果T是一些不支持+的隨機結構,則最終會出現異常(我認爲)。

+0

動態的可怕使用,特別是考慮到運營商不是虛擬的......我想它會「正常工作」它的魔術盒。 (我更喜歡結構類型* *: - /) – 2012-02-18 04:55:44

+0

@pst - 同意,但它確實發生了工作。儘管我明白這一點。 – 2012-02-18 04:59:01

1

你可以把這個只是作爲一個抽象基類,並推導出指定T值,並規定總

public abstract class NumberContainer<T> 
    where T: struct 
{ 
    public T ValueA { get; private set; } 
    public T ValueB { get; private set; } 
    public abstract T Total(); 
} 

public class IntContainer : NumberContainer<int> 
{ 
    public override int Total() 
    { 
     return ValueA + ValueB; 
    } 
} 
+1

如果一個'int'可以轉換爲'T',那麼這不會是一個問題。你的代碼不能編譯。 – 2012-02-18 04:25:04

+0

傻我。由於現在有幾個使用動態和鏈接的解決方案,因此更新了答案以提供備用解決方案 – 2012-02-18 04:40:20