2010-08-30 12 views
7

Duplicar posible:
Solution for overloaded operator constraint in .NET genericsDefinir un genérico que implementa el operador +

Tengo un problema que estoy trabajando, en la actualidad se está trabajando para int s Pero lo quiero para trabajar para todas las clases que se pueden agregar usando el operador +. ¿Hay alguna manera de definir esto en el genérico? Por ejemplo,

public List<T> Foo<T>() where T : ISummable 

¿Hay alguna manera de hacer esto?

EDIT:
El rendimiento de pasar a un delegado para hacer la suma en lugar de usar + = con un tipo de Int fue un 540% más lento en el mejor de los casos. Investigando posible otra solución

Solución final:
Gracias a todos por sus sugerencias. Terminé con una solución que no es demasiado lenta e impone la verificación en tiempo de compilación. No puedo tomar todo el crédito ya que un colega me ayudó a llegar a esto. De todos modos, aquí está:

implementar una interfaz con todos los operadores necesarios en ella en forma de funciones

public interface IFoo<InputType, OutputType> 
{ 
    //Adds A to B and returns a value of type OutputType 
    OutputType Add(InputType a, InputType b); 
    //Subtracts A from B and returns a value of type OutputType 
    OutputType Subtract(InputType a, InputType b); 
} 

Crear la clase que desea definir, pero en lugar de la cláusula WHERE, utilizar una instancia inyectada de dependencia de la interfaz IFoo. el OutputType generalmente será doble porque la naturaleza de las operaciones es matemática.

public class Bar<T> 
{ 
    private readonly IFoo<T,double> _operators; 

    public Bar(IFoo<T, double> operators) 
    { 
     _operators = operators; 
    } 
} 

ahora cuando se utiliza esta clase, se definen las reglas para la operación de la siguiente manera:

private class Foo : IFoo<int, double> 
{ 
    public double Add(int a, int b) 
    { 
     return (double)(a+b); 
    } 
    public double Subtract(int a, int b) 
    { 
     return (double)(a-b); 
    } 
} 

allí tendría que utilizar de esta manera:

Foo inttoDoubleOperations = new Foo(); 
Bar myClass = new Bar(Foo); 

de esa manera todas las operaciones se aplican en tiempo de compilación :)

enjoy!

+1

No, no directamente. Sin embargo, hay un artículo sobre CodeProject que simula esto. – leppie

+0

Gracias por su respuesta. ¿Me puede enviar un enlace a la solución? – TerrorAustralis

+0

Por qué no tienen método en el ISummable que se pueden añadir dos T como T Agregar (T primera, T segundos)? Usando el operador + para la suma IMO involucraría el método de invocación de reflexión op_Addition. – VinayC

Respuesta

8

Esta es una nueva característica muy solicitada comúnmente para C#: la capacidad de especificar restricciones de parámetros más genéricas que las que ya tenemos. Los operadores se encuentran entre los más solicitados. Sin embargo, C# no lo admite actualmente.

soluciones posibles:

  • pase un delegado a cualquier método que tiene que hacer la suma. Esta es la opción más segura, pero por supuesto es molesta si necesita llamar a ese método con frecuencia. Por ejemplo:

    public class Generic<T> { 
        public void DoSomething(T anItem, T anotherItem, Func<T, T, T> add) { 
         // instead of 
         Blah(anItem + anotherItem); 
         // have to write: 
         Blah(add(anItem, anotherItem)); 
        } 
    } 
    
    Generic<int> genInt = ...; 
    // and then instead of ... 
    genInt.DoSomething(1, 2); 
    // have to write: 
    genInt.DoSomething(1, 2, (a, b) => a + b); 
    
  • Declarar su propia interfaz IAddable. entonces usted puede utilizar como una restricción de parámetro de tipo genérico, pero es obvio que no se puede utilizar como parámetro int a continuación. Usted tendría que utilizar un struct de su propia que contiene sólo una int y que implementa IAddable:

    public interface IAddable<T> { 
        T Add(T other); 
    } 
      
    public struct Integer : IAddable<Integer> { 
        public int Value; 
        public Integer(int value) { Value = value; } 
        public Integer Add(Integer other) { return new Integer(Value + other.Value); } 
    } 
    
    // then instead of 
    Generic<int> blah = ...; 
    // have to write: 
    Generic<Integer> blah = ...; 
    
  • dynamic. Otra solución posible es usar dynamic, pero esto es bastante raro y completamente inseguro: le permitirá pasar de cualquier tipo y llamar a cualquier método u operador, y solo se bloqueará en el tiempo de ejecución, no en tiempo de compilación.

+0

Gracias, puedo terminar yendo con el enfoque de pasar un delegado. Parece una solución razonable y no agregará demasiado esfuerzo en la parte del usuario. ¡Gracias amigo! – TerrorAustralis

1

En C# 4.0 es la nueva palabra clave dinámica que le permite realizar esto en tiempo de ejecución. En versiones anteriores era posible pero demasiado turbio y complicado para mí. Pero siempre se puede pasar a un delegado que realizará adiciones dentro de genérico. De lo contrario, no es posible porque no hay ISummable, IAdditive y, en términos generales, no hay forma de saber si algo es aditivo * en el momento de la compilación. Si desea más comentarios, lo agregaré más adelante. BR.

  • Es decir, a excepción de hacer que usted sea dueño de IAdditive y marque algunos tipos con ellos, pero no funcionará, por ejemplo, con ints.
+0

¡Gracias por su respuesta! Le das en el clavo justo en la cabeza con tu comentario sobre IAdditive. No puedo trabajarlo para ints y otras clases/estructuras preimplementadas – TerrorAustralis

Cuestiones relacionadas