web-dev-qa-db-fra.com

C # Ajout de deux valeurs génériques

Quelqu'un peut-il expliquer pourquoi cela ne fonctionnera pas? J'essayais de pouvoir ajouter deux valeurs indépendamment du type numérique.

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

Lorsque je compile cela, j'obtiens l'erreur suivante:

Operator '+' cannot be applied to operands of type 'T' and 'T'
31
Andy Evans

Aucune contrainte générique ne vous permet d'imposer une surcharge d'opérateur. Vous pouvez jeter un oeil à la bibliothèque suivante . Si vous utilisez .NET 4.0, vous pouvez également utiliser le mot clé dynamic:

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

Évidemment, cela n’applique aucune sécurité de compilation, ce à quoi sont destinés les génériques. Le seul moyen d'appliquer la sécurité du temps de compilation est d'appliquer des contraintes génériques. Et pour votre scénario, aucune contrainte n'est disponible. Ce n'est qu'un truc pour tromper le compilateur. Si l'appelant de la méthode Add ne passe pas les types qui fonctionnent avec l'opérateur +, le code lève une exception lors de l'exécution.

53
Darin Dimitrov

Les solutions données ici fonctionnent bien, mais je pensais en ajouter une autre qui utilise des expressions

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 cette façon, vous créez un Func<T, T, T> qui effectue l’ajout . L’explication complète se trouve dans cet article .

24
Adi Lester

Le compilateur ne connaît pas le type T, il ne peut donc pas trouver un opérateur surchargé + défini n'importe où ...

Le mieux que vous puissiez faire actuellement est de déclarer votre méthode en tant que telle (puisque tous les types numériques sont convertibles en double):

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

ou si vous êtes sûr qu'un opérateur + approprié sera défini:

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

Mis à jour

ou une combinaison des deux:

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

C'est un problème que je venais d'avoir quand je voulais une méthode générique qui puisse fonctionner sur des listes de nombres arbitraires, par exemple:

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

La solution que j'ai trouvée consistait à utiliser une expression lambda:

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

Que vous appelez ensuite par

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

Évidemment, dans certains cas, vous pouvez aussi bien avoir + à l'intérieur du code au lieu d'expressions lambda, mais si vous besoin d'exécuter des opérations mathématiques de manière générique, c'était la chose la plus simple que je pouvais trouver qui soit compilée sûr.

5
Brainfloat
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);
}
4
Ira

Essayez ce code. Ceci est un code générique pour addition.

public static dynamic AddAllType(dynamic x, dynamic y)
{
    return  x + y;
}
2
Arun Kumar Upadhyay
        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);

        }
1
siva

Cela empêche les développeurs d'écrire du code buggy. Quelques questions pour mieux expliquer la question:

1> Le compilateur connaît-il le type [Non, car c’est un type générique] . 2> Peut-il accepter les objets en tant que paramètre [Oui, c’est pourquoi il ne saura pas quoi en faire -> code buggy]

Depuis, vous voulez éviter que votre code soit bogué, C # ne vous permet pas d'avoir "+" - "et d'autres opérateurs.

Solution: Vous pouvez utiliser les types "dynamic", "var" et en renvoyer la somme, si nécessaire.

1
KamalDeep

Parce que personne n'a répondu en fournissant une solution en utilisant objet. Par conséquent, j'ajoute ma solution. En cela, vous devez convertir vos valeurs génériques en objet.

Voici donc le code de travail:

public static T Add<T>(T number1, T number2)
{
    object a = number1;
    object b = number2;
    return (T)(object)((int)a * (int)b).ToString();
}
0
yogihosting