2012-07-28 68 views
1

我知道有很多問題上讓喜歡本
"Operator 'whatever' cannot be applied to operands of type 'T'(無論可++,+ =或< =等等等等,但忍耐一下,我想問問不同的東西。在C#5.0中改進了泛型類型的特性/運算符重載嗎?

比方說,我有這個代碼

public class GenericCls<T> where T : struct 
{ 
    public static T AddValues(params T[] values) 
    { 
     T sum = default(T); 
     if (values != null) 
     { 
      for (int i = 0; i < values.Length; i++) 
      { 
       sum += values[i]; 
      } 
     } 
     return sum; 
    } 
} 

即使我做了我喜歡的類型結構,和值類型我得到的錯誤 Operator '+=' cannot be applied to operands of type 'T' and 'T'

如果我儘量隱蔽,並應用值類型約束,它說: Constraint cannot be special class 'System.ValueType'

如果我試圖把在for循環爲T類型的參數,這樣做..

public class GenericCls<T> where T : struct, IComparable<T>, IEquatable<T> 
{ 
    public static T AddValues(params T[] values) 
    { 
     T sum = default(T); 
     if (values != null) 
     { 
      for (T i = default(T); i < values.Length; i++) 
      { 
       sum += values[i]; 
      } 
     } 
     return sum; 
    } 
} 

我仍然得到錯誤

Operator '<' cannot be applied to operands of type 'T' and 'int'
Operator '++' cannot be applied to operand of type 'T'
Cannot implicitly convert type 'T' to 'int'

無論如何,我無法讓它工作。我正在使用VS2010(C#4.0,.NET 4.0)。所以我想知道什麼時候C#5.0將最終與VS2012一起發佈(據我所知,他們仍然處於測試階段吧?)它會照顧這些問題嗎?還是我們再次對泛型使用有太多限制?

+1

不 - 你能做的最好的是傳遞'Func鍵'你的方法,你要執行的操作。然後你可以使用'values.Aggregate(default(T),operatorFunc)'。 – Lee 2012-07-28 13:14:51

+0

下面的詳細信息*一些突破性的變化5,有些可能適用於您的問題:http://msdn.microsoft.com/en-us/library/hh678682(v=vs.110).aspx – 2012-07-28 14:44:37

回答

2

這可能沒有語言改進,但你必須使用一些技巧,不能將其應用於現有的數字類型,但必須創建新的。其中之一是奇怪的循環模式class C<T> : where T : C<T>。另一個技巧是使用靜態委託進行操作。我定義了數字類型像這樣(爲簡單起見,我只定義了加法):

public abstract class Numeric<T> 
    where T : Numeric<T> 
{ 
    public static Func<T, T, T> Add; 

    public static T operator +(Numeric<T> x, Numeric<T> y) 
    { 
     if (x == null) { 
      return (T)y; 
     } 
     if (y == null) { 
      return (T)x; 
     } 
     return Add((T)x, (T)y); 
    } 
} 

需要注意的是,我們有重載運算符時,至少指定一個類型爲Numeric<T>(一種必須始終類重載操作符)。還請注意,我們可以投Numeric<T>T,因爲通用約束where T : Numeric<T>

現在我們可以聲明一個這樣的計算器。由於Numeric<T>超載+運營商,我們可以在這裏使用+=

public class Calculator<T> where T : Numeric<T> 
{ 
    public static T AddValues(params T[] values) 
    { 
     T sum = default(T); 
     if (values != null) { 
      for (int i = 0; i < values.Length; i++) { 
       sum += values[i]; 
      } 
     } 
     return sum; 
    } 
} 

現在讓我們定義一個具體的Numeric類。在靜態構造函數中,我們定義了靜態的Add委託。由於運算符是靜態的,因此這個委託必須是靜態的,因爲它是從運算符方法中調用的,並且由於靜態成員不能是虛擬的,所以我們必須使用這種委託技巧。

public class Complex : Numeric<Complex> 
{ 
    static Complex() 
    { 
     Add = (x, y) => new Complex(x.Re + y.Re, x.Im + y.Im); 
    } 

    public double Re { get; private set; } 
    public double Im { get; private set; } 

    public Complex(double re, double im) 
    { 
     Re = re; 
     Im = im; 
    } 

    public override string ToString() 
    { 
     return String.Format("({0}, {1})", Re, Im); 
    } 
} 

現在讓我們來測試這個棘手的建設

static class Test 
{ 
    public static void AddComplexNumbers() 
    { 
     // Using the calculator 
     var numbers = new Complex[] { new Complex(2, 7), new Complex(6, -2) }; 
     var result = Calculator<Complex>.AddValues(numbers); 
     Console.WriteLine(result); // ==> (8, 5) 

     // Directly 
     var c1 = new Complex(2, 7); 
     var c2 = new Complex(6, -2); 
     result = c1 + c2; 
     Console.WriteLine(result); // ==> (8, 5) 

    } 
} 
+0

@TrueWill:感謝您的編輯。 – 2012-07-28 16:11:37

1

不,它不會改善這個問題。 C#5將提供異步等待和一些次要功能。但不是泛型的擴展版本,適用於方法/運算符重載。

作爲比較,您可以使用IComparer<T>IComparable<T>作爲解決方法,但對於算術沒有好的解決方案。有一些技巧,但是他們要麼使API變得醜陋,要麼很慢。


如果我儘量隱蔽,並應用值類型約束,它說:「約束不能特殊類System.ValueType

這種約束的等效是struct關鍵字即where T: struct。但是限制價值類型在這裏並沒有帶來任何收益。爲什麼呢?有值類型不支持算術,並且有參考類型。所以,價值類型與你所需要的是正交的。

+0

我didn不知道,我認爲如果我應用'ValueType'約束,我可以使算術運算符可用。 – Razort4x 2012-07-28 13:18:20

+0

@ OlivierJacot-Descombes您對錯誤答案進行了評論 – CodesInChaos 2012-07-28 15:58:47

0

不幸的是,目前處於RC狀態的C#5.0沒有任何變化。它主要側重於異步編程。

+1

不正確,匿名方法和for循環中的lambdas變量如何被捕獲。命名參數的副作用如何評估的順序已更改,以及使用命名參數的調用的重載解析已更改。另外,在某些情況下,使用委託時的重載解析已經改變。而這些只是「突變」。 – 2012-07-28 14:43:17

+0

+1。 @PeterRitchie:user1527329表示C#5.0主要是**,並非專門針對'async'。實際上,'async'和'await'關鍵字似乎是唯一新的語法語言擴展,並且實際上代表了最重要的新功能或更改功能。 – 2012-07-28 15:03:18

+0

「沒有改變」?這是錯誤的。 – 2012-07-28 15:16:23