有人可以解释为什么这不起作用?无论数字类型如何,我都试图能够添加两个值。
public static T Add<T> (T number1, T number2)
{
return number1 + number2;
}
编译时,我收到以下错误:
Operator '+' cannot be applied to operands of type 'T' and 'T'
答案 0 :(得分:57)
没有通用约束允许您强制执行运算符重载。您可以查看following library。或者,如果您使用的是.NET 4.0,则可以使用dynamic
关键字:
public static T Add<T>(T number1, T number2)
{
dynamic a = number1;
dynamic b = number2;
return a + b;
}
显然,这并不适用于任何编译时安全性,这是泛型的意思。应用编译时安全性的唯一方法是强制执行通用约束。对于您的场景,没有可用的约束。这只是欺骗编译器的技巧。如果Add方法的调用者没有传递与+运算符一起使用的类型,则代码将在运行时抛出异常。
答案 1 :(得分:24)
这里给出的解决方案运行良好,但我想我会添加另一个使用表达式
的解决方案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>
。
完整的解释可以在this article。
答案 2 :(得分:9)
编译器不知道类型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);
}
答案 3 :(得分:5)
当我想要一个可以在任意数字列表上工作的泛型方法时,我就遇到了这个问题,例如:
public T Calculate<T>(IEnumerable<T> numbers);
我找到的解决方案是使用lambda表达式:
public T Calculate<T>(Func<T, T, T> add, IEnumerable<T> numbers);
然后通过
调用var sum = this.Calculate((a, b) => a + b, someListOfNumbers);
显然在某些情况下,您可能只是在代码中使用+而不是lambda表达式,但如果您需要以通用方式执行数学运算,这是我可以提出的最简单的方法这是编译安全的。
答案 4 :(得分:4)
Since this is generic type without a constraint compiler has no knowledge if the types involved will have '+' overloaded hence the compiler error
These are some workarounds
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());
Below code could let you build same but evaluated at run time so not run time safe
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);
}
答案 5 :(得分:2)
尝试此代码。这是添加的通用代码。
public static dynamic AddAllType(dynamic x, dynamic y)
{
return x + y;
}
答案 6 :(得分:1)
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);
}
答案 7 :(得分:1)
这可以防止开发人员编写错误的代码。几个问题不能更好地解释这个问题:
1&GT;编译器是否知道类型[否,因为它是通用类型]。 2 - ;它可以接受对象作为参数[是的,它可以并且因此它不知道如何处理它们 - &gt;越野车代码]
因为,您希望防止您的代码出错,C#不允许您使用&#39; +&#39; &#39; - &#39;和其他运营商。
解决方案: 你可以使用&#34; dynamic&#34;,&#34; var&#34;如果需要,可以输入并返回它们的总和。
答案 8 :(得分:0)
如果您不想(或不能)在运行时使用动态类型或生成代码,那么我可以从EqualityComparer
实现中借用另一种方法。这有点冗长,但是使用“经典” .NET工具的另一种可能性。
首先,您定义一个类似于“特征”的通用接口,定义您想要的添加方法:
/// <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
学校数学从未如此简单!也许。并不是的。它是机密的。
答案 9 :(得分:0)
如果您可以将泛型类型 T 包装在某种“容器”中,则可以使用以下方法。我为 Total
和 int
提供了一种方法 (double
),但您可以轻松添加其他类型和方法。
顺便说一下,这类似于 Linq 如何为 Sum
定义扩展方法(例如 IEnumerable<T>
)。
internal struct GenericContainer<T> {
internal T A { get; set; }
internal T B { get; set; }
}
/// <summary>
/// Extension methods for GenericContainer<T>
/// </summary>
internal static class GenericContainerExtensions {
internal static int Total(this GenericContainer<int> gc) {
return gc.A + gc.B;
}
internal static double Total(this GenericContainer<double> gc) {
return gc.A + gc.B;
}
}
class Program {
static void Main(string[] args) {
var gc = new GenericContainer<double>() { A = 3.3, B = 4.4 };
Console.WriteLine($"gc.Total() = {gc.Total()}");
}
}
答案 10 :(得分:-1)
因为没有人通过使用对象提供解决方案来回答。因此我正在添加我的解决方案。在此,您必须将通用值转换为object。
所以这是工作代码:
public static T Add<T>(T number1, T number2)
{
object a = number1;
object b = number2;
return (T)(object)((int)a * (int)b).ToString();
}
答案 11 :(得分:-2)
正如您从错误消息中看到的那样,运算符'+'无法应用。 发生这种情况是因为编译器对T类型一无所知。 它甚至都不知道这是不是一个班级。