2011-11-14 16 views
20

Czy ktoś może wyjaśnić, dlaczego to nie zadziała? Próbowałem móc dodać dwie wartości niezależnie od typu liczbowego.C# Dodawanie dwóch ogólnych wartości

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

Kiedy skompilować tego, pojawia się następujący błąd:

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

Kompilator C# robi to, aby nie pisać kodu błędu. Jeśli T nie jest znane kompilatorowi, nie wie, jak dodać wartości T. Nie zna też typu wyniku T, w tym przypadku dodania. – JonH

+0

Czy argumenty muszą być "typu numerycznego"? –

Odpowiedz

40

Brak ogólnego ograniczenia, które pozwala wymuszać przeciążenie operatora. Możesz rzucić okiem na following library. Alternatywnie, jeśli używasz .NET 4.0 można użyć dynamic kluczowe:

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

Oczywiście to nie stosuje się żadnych kompilacji bezpieczeństwa w czasie, który jest co generyczne są przeznaczone dla. Jedynym sposobem na zastosowanie czasu kompilacji jest wymuszenie ogólnych ograniczeń. I dla twojego scenariusza nie ma ograniczeń. To tylko sztuczka, aby oszukać kompilator. Jeśli osoba wywołująca metodę Add nie przekazuje typów współpracujących z operatorem +, kod wygeneruje wyjątek w czasie wykonywania.

+1

+1 za wyjaśnienie i wynik podania złych danych. – JonH

+0

Myślę, że teraz jest ograniczenie. Szczegóły [tutaj] (https://msdn.microsoft.com/en-us/library/bb384067.aspx) – Aamir

+0

@Aamir Ograniczenie "gdzie" zawsze istniało. Chodzi o to, że nie ma sposobu, aby określić "gdzie T można dodać do innego Ts" w tym miejscu klauzula :) – Frans

-2

Jak widać z komunikatu błędu operatora „+” nie mogą być stosowane. Dzieje się tak, ponieważ kompilator nic nie wie o typie T. Nie wie nawet, czy jest to klasa, czy nie.

+2

Nie jest to dobra odpowiedź. – JonH

+0

@JonH mmm .. może masz rację. Nie wiem, jak wyjaśnić w kilku słowach, że generics C# jest bardzo ograniczone w porównaniu do szablonów C++ – VMykyt

+1

Nie ma to nic wspólnego z ograniczeniami. Jeśli właściwie zrobione, praktycznie wszystko jest możliwe. Oryginalna odpowiedź brzmiała "jak widzisz z operatora komunikatu o błędzie + nie można go zastosować". To nie jest dobra odpowiedź, nie padłem, ale tak nie jest. – JonH

8

typ T nie jest znany przez kompilator, więc to nie może znaleźć przeciążony operator + zdefiniowany nigdzie ...

Najlepiej można obecnie zrobić, to zadeklarować swoją metodę jako takie (ponieważ wszystkie typy liczbowe są wymienialne na podwójne):

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

lub jeśli jesteś pewien odpowiedni operator + zostaną określone: ​​

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

Updated

lub kombinacja tych dwóch:

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

Ułamków dziesiętnych nie można konwertować do podwójnego niejawnego. – kol

+2

@kol Dobry punkt, usunięty niejawnie z mojej odpowiedzi. –

3

Jest to problem, który miałem tylko gdy chciałem ogólny sposób, który mógłby pracować na dowolnych list numerów, na przykład:

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

rozwiązanie znalazłem użycie wyrażenia lambda:

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

które Można by n wezwanie

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

Oczywiście w niektórych przypadkach może równie dobrze mieć + wewnątrz kodu zamiast wyrażeń lambda, ale jeśli potrzebie do wykonywania operacji matematycznych w sposób ogólny to było najłatwiejsze mogłem wymyślić, że jest to bezpieczne.

15

Rozwiązania podane działa dobrze, ale pomyślałem, że dodam jeszcze jeden, który używa wyrażenia

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

ten sposób tworzysz Func<T, T, T> która wykonuje dodawanie. Pełne wyjaśnienie można znaleźć w 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

Zapobiega to programistom pisać kod buggy. Kilka pytań, aby lepiej wyjaśnić pytanie:

1> Czy kompilator zna typ [Nie, ponieważ jest to typ ogólny]. 2> Czy akceptuje obiekty jako parametr [Tak, może i dlatego nie będzie wiedział, co z nimi zrobić -> kod błędu]

Ponieważ, chcesz zapobiec błędom swojego kodu, C# nie pozwala na używanie "+" - "i innych operatorów.

Rozwiązanie: można użyć typu "dynamic", "var" i może je zwrócić, jeśli jest to wymagane.

1

Ponieważ nikt nie odpowiedział, dostarczając rozwiązania za pomocą obiektu. Dlatego dodaję moje rozwiązanie. W tym musisz rzucić swoje ogólne wartości do obiektu.

Więc jest to kod pracy:

1

Spróbuj tego kodu. Jest to ogólny kod dodawania.

public static dynamic AddAllType(dynamic x, dynamic y) 
{ 
    return x + y; 
} 
Powiązane problemy