2011-11-18 12 views
12

Ho scritto una classe generico:Come posso sottrarre due oggetti generici (T - T) in C# (Esempio: DateTime - DateTime)?

public class Interval<T> where T : IComparable // for checking that Start < End 
{ 
    public T Start { get; set; } 
    public T End { get; set; } 
    ... 
} 

e io uso questa classe con DateTime, int, ecc

Ho bisogno di un proprietà durata che restituisce una durata simile:

public object Duration 
{ 
    get 
    { 
     return End - Start; 
    } 
} 

Ma quando questa proprietà è inclusa nella mia classe, il compilatore genera un errore logico sull'operatore -.

Cosa posso fare normalmente per raggiungere questo obiettivo o dovrei ignorare?

+1

E come fa il compilatore a sapere che il tipo che stai usando ha definito l'operatore '-'? – Oded

+0

Questo potrebbe aiutare: http://stackoverflow.com/questions/171664/how-to-turn-these-3-methods-into-one-using-c-sharp-generics, controlla Marc Gravells post su aritmetica generica. – Alex

+0

Possibile duplicato: http://stackoverflow.com/questions/5516459/constrain-type-to-allow-addition-subtraction-operations-in-c-sharp – Reddog

risposta

3

Provare qualcosa di simile this:

static void Main(string[] args) 
{ 
    Tuple<int, bool> value = JustAMethod<int>(5, 3); 
    if (value.Item2) 
    { 
     Console.WriteLine(value.Item1); 
    } 
    else 
    { 
     Console.WriteLine("Can't substract."); 
    } 
} 
public static Tuple<T, bool> JustAMethod<T>(T arg1, T arg2) 
{ 
    dynamic dArg1 = (dynamic)arg1; 
    dynamic dArg2 = (dynamic)arg2; 
    dynamic ret; 
    try 
    { 
     ret = dArg1 - dArg2; 
     return new Tuple<T, bool>(ret, true); 
    } 
    catch 
    { 
     return new Tuple<T, bool>(default(T), false); 
    } 
} 

Come funziona: in primo luogo, si convertono gli argomenti in un tipo dinamico e si possono facilmente utilizzare gli operatori sul tipo dinamico. Se non si è in grado di utilizzare gli operatori, verrà generata un'eccezione in fase di runtime.Quindi, se provi a sottrarre due oggetti che in realtà non puoi sottrarre, cattureremo l'eccezione e restituiremo false come secondo elemento nello Tuple.

1

Il compilatore esegue questa operazione in modo da non scrivere codice buggato, è l'intero punto di generica e il concetto di programmazione di tipo sicuro.

Se è necessario un metodo che sottrae le date, scriverne uno che accetta una data e, se è necessario un altro per i numeri interi, indovinate cosa si dovrebbe scrivere per i numeri interi. I generici non sono presenti in modo che il compilatore possa assumersi la responsabilità per qualsiasi tipo. Pensaci e se volessi la differenza tra due oggetti, come farei con il tuo metodo generico?

O come menzionato da @Reed Copsey, è possibile vincolare una classe.

+0

Sì, ma questa non è la mia domanda, dico come non perché? –

+0

E ti ho dato una risposta 'scrivi un metodo per int e ne scrivi uno per data', i generici forniscono il tipo sicurezza, non si tratta del perché è quello che è. – JonH

+0

Mi alzo per quello che ho detto, disposto a prendere il downvote @RedHat. – JonH

7

Questo non è possibile con i generici in C# - almeno non direttamente. È stato un highly requested feature on Connect per molto tempo.

È necessario che i tipi implementino un'interfaccia con un membro che può essere utilizzato e vincoli la classe, oppure utilizzare una delle soluzioni elencate nel bug Connect (nessuna delle quali è perfetta), oppure un approccio separato come MiscUtil's generic operators.

+1

+1 per l'approccio dell'interfaccia. – MPelletier

1

Anche se questo può sembrare un limite importante, è necessario ricordare che i generici sono generici. Naturalmente, il tipo System.Int32 può funzionare perfettamente con gli operatori binari di C#. Tuttavia, per amor di discussione, se <T> erano un tipo di classe personalizzata o la struttura, il compilatore non può assumere che ha sovraccaricato i +, -, * e / operatori.

4

questo lavoro

public object Duration 
{ 
    get 
    { 
     return (dynamic)End - (dynamic)Start; 
    } 
} 

ma nessun controllo, e lento