2011-11-18 27 views
12

escribí una clase genérica :¿Cómo puedo restar dos objetos genéricos (T - T) en C# (Ejemplo: DateTime - DateTime)?

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

y lo uso con esta clase DateTime, int, etc.

Necesito un Duración propiedad que devuelve una duración como:

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

Pero cuando esta propiedad está incluida en mi clase, el compilador genera un error lógico en el operador -.

¿Qué puedo hacer para lograr este objetivo normalmente o debería ignorar?

+1

¿Y cómo sabe el compilador que el tipo que está utilizando tiene definido el operador '-'? – Oded

+0

Esto podría ayudar: http://stackoverflow.com/questions/171664/how-to-turn-these-3-methods- into-one-using-c-sharp-generics, consulte la publicación de Marc Gravells sobre aritmética genérica. – Alex

+0

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

Respuesta

3

Pruebe algo como esto:

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

Cómo funciona esto: primero, convierte los argumentos a un tipo dinámico, y puede usar fácilmente operadores en el tipo dinámico. Si no pudiera usar los operadores, se lanzaría una excepción en el tiempo de ejecución.Por lo tanto, si intenta sustraer dos objetos que en realidad no puede restar, detectaremos la excepción y devolveremos false como segundo elemento en el Tuple.

1

El compilador hace esto para que no escriba código defectuoso, es el objetivo de los genéricos y el concepto de tipo de programación segura.

Si necesita un método que sustrae fechas, escriba uno que acepte una fecha, y si necesita otra para enteros, adivine qué debe escribir uno para enteros. Los genéricos no están ahí para que el compilador pueda asumir la responsabilidad de cualquier tipo. Piénselo, si quisiera la diferencia entre dos objetos, ¿cómo lo haría con su método genérico?

O como @Reed Copsey mencionó que puede limitar una clase a ella.

+0

Sí, pero esta no es mi pregunta, digo ¿por qué no? –

+0

Y te di una respuesta 'escribes un método para int y escribes uno para fecha ', los genéricos proporcionan seguridad tipo, no se trata de por qué es lo que es. – JonH

+0

Defiendo lo que dije, dispuesto a tomar el voto en negativo @RedHat. – JonH

7

Esto no es posible con genéricos en C# - al menos no directamente. Ha sido un highly requested feature on Connect durante mucho tiempo.

Tendrá que hacer que sus tipos implementen alguna interfaz que tenga un miembro que pueda usarse, y restringir la clase a eso, o usar una de las soluciones alternativas enumeradas en el error Connect (ninguna de las cuales es perfecta) o un enfoque separado como MiscUtil's generic operators.

+1

+1 para el enfoque de interfaz. – MPelletier

1

Si bien esto puede parecer una restricción importante, debe recordar que genéricos son genéricos. Por supuesto, el tipo System.Int32 puede funcionar bien con los operadores binarios de C#. Sin embargo, en aras de la argumentación, si <T> era una clase o tipo de estructura personalizada, el compilador no puede suponer que ha sobrecargado los operadores +, -, * y /.

4

este trabajo

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

pero sin verificación, y lento

Cuestiones relacionadas