有人能解释一下为什么这个不行吗?我想实现无论数字类型如何都可以将两个值相加。
public static T Add<T> (T number1, T number2)
{
return number1 + number2;
}
当我编译这个时,会出现以下错误:
Operator '+' cannot be applied to operands of type 'T' and 'T'
有人能解释一下为什么这个不行吗?我想实现无论数字类型如何都可以将两个值相加。
public static T Add<T> (T number1, T number2)
{
return number1 + number2;
}
Operator '+' cannot be applied to operands of type 'T' and 'T'
没有通用的约束条件可以强制执行运算符重载。您可以查看以下库。或者,如果您使用的是.NET 4.0,则可以使用dynamic
关键字:
public static T Add<T>(T number1, T number2)
{
dynamic a = number1;
dynamic b = number2;
return a + b;
}
显然,这不会提供任何编译时的安全性,这正是泛型的作用。唯一实现编译时安全性的方法是强制执行泛型约束。而对于您的情况,没有可用的约束条件。这只是欺骗编译器的技巧。如果调用Add方法的调用方未传递与+运算符兼容的类型,则代码将在运行时抛出异常。
public static T Add<T>(T a, T b)
{
// Declare the parameters
var paramA = Expression.Parameter(typeof(T), "a");
var paramB = Expression.Parameter(typeof(T), "b");
// Add the parameters together
BinaryExpression body = Expression.Add(paramA, paramB);
// Compile it
Func<T, T, T> add = Expression.Lambda<Func<T, T, T>>(body, paramA, paramB).Compile();
// Call it
return add(a, b);
}
这样,您就创建了一个执行加法的 Func<T, T, T>
。
完整的解释可以在这篇文章中找到。
编译器不认识类型T,因此无法找到任何定义过的重载+运算符...
目前最好的方法是将您的方法声明为如下形式(因为所有数值类型都可以转换为double):
public static double Add (double number1, double number2)
{
return number1 + number2;
}
或者如果您确定适当的+运算符已定义:
public static T Add<T>(T number1, T number2)
{
dynamic dynamic1 = number1;
dynamic dynamic2 = number2;
return dynamic1 + dynamic2;
}
更新
或者两者的组合:
public static T Add<T>(T in1, T in2)
{
var d1 = Convert.ToDouble(in1);
var d2 = Convert.ToDouble(in2);
return (T)(dynamic)(d1 + d2);
}
我最近在查找通用方法的时候遇到了这个问题,这种方法可以适用于任意数字列表,例如:
public T Calculate<T>(IEnumerable<T> numbers);
public T Calculate<T>(Func<T, T, T> add, IEnumerable<T> numbers);
然后您可以通过以下方式进行调用:
var sum = this.Calculate((a, b) => a + b, someListOfNumbers);
由于这是一个没有约束的通用类型,编译器不知道涉及的类型是否有“+”重载,因此会出现编译器错误。
以下是一些解决方法:
public static TResult Add<T1, T2, TResult>(T1 left, T2 right, Func<T1, T2, TResult> AddMethod)
{
return AddMethod(left, right);
}
var finalLabel = Add("something", 3,(a,b) => a + b.ToString());
public static T AddExpression<T>(T left, T right)
{
ParameterExpression leftOperand = Expression.Parameter(typeof(T), "left");
ParameterExpression rightOperand = Expression.Parameter(typeof(T), "right");
BinaryExpression body = Expression.Add(leftOperand, rightOperand);
Expression<Func<T, T, T>> adder = Expression.Lambda<Func<T, T, T>>(
body, leftOperand, rightOperand);
Func<T, T, T> theDelegate = adder.Compile();
return theDelegate(left, right);
}
Aggregate
。 - Bananach尝试这段代码。这是一个通用的加法代码。
public static dynamic AddAllType(dynamic x, dynamic y)
{
return x + y;
}
这可以防止开发人员编写有错误的代码。以下是一些问题,以更好地解释此问题:
由于您想要防止代码出错,C# 不允许您使用 '+' '-' 和其他运算符。
解决方案:您可以使用 "dynamic","var" 类型,并在需要时返回它们的总和。
public class generic<T>
{
T result;
public generic(T eval1, T eval2)
{
dynamic a = eval1;
dynamic b = eval2;
result = a + b;
Console.WriteLine(result);
Console.ReadLine();
}
static void Main(string[] args)
{
generic<int> genobj = new generic<int>(20,30);
}
/// <summary>
/// Represents an interface defining the addition calculation for generic types.
/// </summary>
public interface IAddition<T>
{
/// <summary>
/// Calculates the addition result of <paramref name="left"/> and <paramref name="right"/>.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>The calculation result.</returns>
T Add(T left, T right);
}
float
执行此操作:internal class SingleAddition : IAddition<Single>
{
Single IAddition<Single>.Add(Single left, Single right) => left + right;
}
然后您创建一个通用的静态类,这将是您实际交互的类。它会自动创建并缓存符合其泛型类型的IAddition<T>
接口的实现:
/// <summary>
/// Represents an implementation of addition calculations for generic types.
/// </summary>
/// <typeparam name="T">The type to support the addition calculation.</typeparam>
public static class Addition<T>
{
private static readonly IAddition<T> _implementation = Implement();
/// <summary>
/// Calculates the addition result of <paramref name="left"/> and <paramref name="right"/>.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>The calculation result.</returns>
public static T Add(T left, T right) => _implementation.Add(left, right);
private static IAddition<T> Implement()
{
Type type = typeof(T);
// If T implements IAddition<T> return a GenericAddition<T>.
if (typeof(IAddition<T>).IsAssignableFrom(type))
return (IAddition<T>)Activator.CreateInstance(typeof(GenericAddition<>).MakeGenericType(type));
// Otherwise use a default implementation for primitive types.
switch (type.IsEnum ? Type.GetTypeCode(Enum.GetUnderlyingType(type)) : Type.GetTypeCode(type))
{
case TypeCode.Single:
return (IAddition<T>)new SingleAddition();
default:
throw new NotSupportedException($"Type {type.Name} does not support addition.");
}
}
}
internal sealed class GenericAddition<T> : IAddition<T> where T : IAddition<T>
{
T IAddition<T>.Add(T left, T right) => left.Add(left, right);
}
IAddition<T>
接口 - GenericAddition
实现将负责使用它。Enum
值。Addition<T>
类中看到的那样,它公开了一个Add
方法,最终你将从外部调用它,如下所示:public class SomeStuff<T>
{
public T TestAddition(T left, T right) => Addition<T>.Add(left, right);
}
// Testing in C# interactive:
> SomeStuff<float> floatStuff = new SomeStuff<float>();
> floatStuff.TestAddition(12, 24.34f)
36.34
operator +
(如果可用),而不管实现的接口如何。 - Ray从.NET 7开始,可以使用INumber接口实现此操作。
public static T Add<T> (T number1, T number2) where T : INumber<T>
{
return number1 + number2;
}
更多信息可以在这里找到:https://learn.microsoft.com/en-us/dotnet/standard/generics/math