2011-11-14 10 views
20

¿Alguien puede explicar por qué esto no funciona? Intentaba poder agregar dos valores independientemente del tipo numérico.C# Agregar dos valores genéricos

public static T Add<T> (T number1, T number2) 
{ 
    return number1 + number2; 
} 

Cuando compilo esto, me sale el siguiente error:

Operator '+' cannot be applied to operands of type 'T' and 'T' 
+1

El compilador C# hace esto para que no escriba el código erróneo. Si T es desconocido para el compilador, no sabe cómo agregar valores T. Tampoco conoce el tipo de resultado de T, en este caso la suma. – JonH

+0

¿Los argumentos son forzados a ser "de tipo numérico"? –

Respuesta

40

No existe una restricción genérica que le permita forzar la sobrecarga del operador. Puede echar un vistazo al following library. Alternativamente, si usted está utilizando .NET 4.0 se puede utilizar la palabra clave dynamic:

public static T Add<T>(T number1, T number2) 
{ 
    dynamic a = number1; 
    dynamic b = number2; 
    return a + b; 
} 

Obviamente, esto no se aplica ninguna seguridad de tiempo de compilación que es lo que los genéricos son para. La única forma de aplicar seguridad en tiempo de compilación es aplicar restricciones genéricas. Y para su escenario no hay restricción disponible. Es solo un truco para engañar al compilador. Si la persona que llama del método Agregar no pasa los tipos que funcionan con el operador +, el código arrojará una excepción en el tiempo de ejecución.

+1

+1 para la explicación y el resultado de pasar datos incorrectos. – JonH

+0

Creo que ahora es donde la restricción ... Detalles [aquí] (https://msdn.microsoft.com/en-us/library/bb384067.aspx) – Aamir

+0

@Aamir La restricción "where" siempre ha estado allí. El punto es que no hay forma de especificar "donde T se puede agregar a otros Ts" en esa cláusula where :) – Frans

-2

Como se puede ver desde el mensaje de error del operador '+' no se puede aplicar. Esto ocurre porque el compilador no sabe nada sobre el tipo T. No sabe si esta es una clase o no.

+2

No es una buena respuesta. – JonH

+0

@JonH mmm .. puede ser que tengas razón. No sé cómo explicar en pocas palabras que los genéricos C# son muy limitados en comparación con las plantillas C++ – VMykyt

+1

Esto no tiene nada que ver con las limitaciones. Si se hace correctamente, prácticamente todo es posible. Su respuesta original fue 'como se ve en el operador del mensaje de error + no se puede aplicar'. Esa no es una buena respuesta, no perdoné, pero ese no es el caso. – JonH

8

Tipo T no es conocido por el compilador, por lo que no puede encontrar una sobrecarga + operador definido en cualquier lugar ...

Lo mejor que puede hacer es actualmente el método de declarar como tal (ya que todos los tipos numéricos son convertibles a doble):

public static double Add (double number1, double number2) 
{ 
    return number1 + number2; 
} 

o si no está seguro de un operador adecuado + se definirá:

public static T Add<T>(T number1, T number2) 
{ 
    dynamic dynamic1 = number1; 
    dynamic dynamic2 = number2; 
    return dynamic1 + dynamic2; 
} 

Actualizado

o una combinación de los dos:

public static T Add<T>(T in1, T in2) 
{ 
    var d1 = Convert.ToDouble(in1); 
    var d2 = Convert.ToDouble(in2); 
    return (T)(dynamic)(d1 + d2); 
} 
+1

Los decimales no se pueden convertir al doble implícitamente. – kol

+2

@kol Buen punto, eliminado implícitamente de mi respuesta. –

3

Este es un problema que sólo tenía cuando quería un método genérico que podía funcionar en las listas arbitrarias de números, por ejemplo:

public T Calculate<T>(IEnumerable<T> numbers); 

la solución que encontré fue utilizar una expresión lambda:

public T Calculate<T>(Func<T, T, T> add, IEnumerable<T> numbers); 

¿Qué és el n llamada

var sum = this.Calculate((a, b) => a + b, someListOfNumbers); 

Obviamente, en algunos casos es posible que también acaba de tener + en el código en lugar de expresiones lambda, pero si necesidad para realizar operaciones matemáticas de forma genérica esto era lo más fácil que pude proponer que es compila seguro.

15

Las soluciones que se dan aquí funcionan bien, pero pensé que me gustaría añadir otra que utiliza expresiones

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); 
} 

De esta manera se está creando un Func<T, T, T> que lleva a cabo la adición. La explicación completa se puede encontrar en this article.

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); 

     } 
3
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); 
} 
1

Esto evita que los desarrolladores escribir código erróneo. Algunas preguntas para explicar mejor la pregunta:

1> ¿El compilador conoce el tipo [No, porque es un tipo genérico]. 2> ¿Puede aceptar objetos como parámetro? [Sí, puede y debido a esto no sabrá qué hacer con ellos -> código con errores]

Como quiere evitar que su código tenga errores, C# no le permite tener '+' '-' y otros operadores.

Solución: puede usar el tipo "dinámico", "var" y puede devolver la suma de ellos, si es necesario.

1

Porque nadie respondió proporcionando una solución mediante el uso de objetos. Por lo tanto, estoy agregando mi solución. En esto, debes convertir tus valores genéricos a objeto.

Así que este es el código de trabajo:

1

Pruebe este código. Este es un código genérico para agregar.

public static dynamic AddAllType(dynamic x, dynamic y) 
{ 
    return x + y; 
} 
Cuestiones relacionadas