[英]Has generic type's features/operator overloading improved in C# 5.0?
我知道有很多关于这样的问题
"Operator 'whatever' cannot be applied to operands of type 'T'
(无论是++,+ =或<=等等。但请耐心等待,我想问一些不同的东西。
假设我有这个代码
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;
}
}
即使我已经创建了我的类型结构,并且值类型I得到错误Operator '+=' cannot be applied to operands of type 'T' and 'T'
如果我尝试细微并应用ValueType约束,则表示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一起发布(据我所知他们仍然处于测试阶段?)它会处理这些问题吗? 或者我们是否再次对泛型的使用有如此多的限制?
没有语言改进是可能的,但你必须使用一些技巧,不能将它应用于现有的数字类型,但必须创建新的。 其中之一是奇怪的重复模式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>
(一种类型必须始终是重载运算符的类)。 另请注意,由于where T : Numeric<T>
的通用约束,我们可以将Numeric<T>
为T
现在我们可以声明这样的计算器。 由于Numeric<T>
重载了+
运算符,我们可以使用+=
here。
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
委托。 由于运算符是静态的,因此该委托也必须是静态的,因为它是在operator方法中调用的,并且由于静态成员不能是虚拟的,所以我们必须使用这个委托技巧。
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)
}
}
不,它不会改善这个问题。 C#5将提供async-await和一些次要功能。 但不是与方法/运算符重载一起使用的泛型的扩展版本。
对于比较,您可以使用IComparer<T>
和IComparable<T>
作为解决方法,但对于算术,没有好的解决方案。 有一些技术,但它们要么使API丑陋,要么它们很慢。
如果我试图微妙并应用ValueType约束,它说“约束不能是特殊类
System.ValueType
”
这个约束的等价物是struct
关键字,即where T: struct
。 但是限制价值类型并没有在这里获得任何东西。 为什么会这样呢? 有些值不支持算术,并且有一些引用类型。 因此,作为一种价值类型与您需要的正交。
不幸的是,C#5.0没有任何变化,目前处于RC状态。 它主要关注异步编程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.