2012-07-28 67 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