2008-09-29 17 views
30

¿Qué haría si quiero tener un método genérico que solo acepta tipos que han sobrecargado un operador, por ejemplo, el operador de resta. Intenté utilizar una interfaz como restricción, pero las interfaces no pueden tener sobrecarga del operador.Solución para restricción de operador sobrecargado en genéricos .NET

¿Cuál es la mejor manera de lograr esto?

+1

¿Tiene un ejemplo de donde está intentando para usar esto? No puedo pensar en ninguna parte que sea útil? –

+0

Un método genérico de "suma" sería un ejemplo simple. T Sum (secuencia de IEnumerable ); // donde T tiene el operador '+' – blackwing

+0

posible duplicado de [Definir un genérico que implementa el operador +] (http://stackoverflow.com/questions/3598341/define-a-generic-that-implements-the-operator) – Timwi

Respuesta

37

No hay respuesta inmediata; los operadores son estáticos y no pueden expresarse en restricciones, y las primativas existentes no implementan ninguna interfaz específica (a diferencia de IComparable [<T>] que se puede usar para emular mayor que/menor que).

Sin embargo; si lo que desea que funcione, a continuación, en .NET 3.5 hay algunas opciones ...

He reunido una biblioteca here que permite un acceso eficiente y simple de los operadores con los genéricos - tales como:

T result = Operator.Add(first, second); // implicit <T>; here 

Se puede descargar como parte de MiscUtil

Además, en C# 4.0, esto se hace posible a través de dynamic:

static T Add<T>(T x, T y) { 
    dynamic dx = x, dy = y; 
    return dx + dy; 
} 

También tuve (en un momento) una versión .NET 2.0, pero eso está menos probado. La otra opción es crear una interfaz como

interface ICalc<T> 
{ 
    T Add(T,T)() 
    T Subtract(T,T)() 
} 

etc, pero entonces usted necesita para pasar una ICalc<T>; a través de todos los métodos, que se complica.

+0

Me gusta la capacidad de usar dynamic en .NET 4.0, sin dudas hace las cosas mucho más fáciles. Sin embargo, vale la pena señalar que habrá una implicancia en el rendimiento al usarlo porque tiene que hacer más trabajo en el tiempo de ejecución. Me gustaría saber cuánto impacto tiene, creo que necesita algunos puntos de referencia. –

+0

Benchmark ya hecho; intente el código desde aquí: http://social.msdn.microsoft.com/Forums/en-US/vs2010ctpvbcs/thread/287db1b9-c135-40bc-a1c5-a8a51efbfc65 –

+0

Probé su biblioteca (para .NET 3.5), y tengo una pregunta: ¿por qué no funciona la siguiente línea: MiscUtil.Operator.Add ("A", "B") ;. Según entiendo, debería devolver "AB". – Malki

5

Descubrí que IL realmente puede manejar esto bastante bien. Ex.

ldarg.0 
ldarg.1 
add 
ret 

Compilado en un método genérico, el código se ejecutará bien siempre que se especifique un tipo primitivo. Es posible extender esto para llamar a las funciones del operador en tipos no primitivos.

Ver here.

-1

Hay un código robado de los internautas que uso mucho para esto. Busca o construye usando IL operadores aritméticos básicos. Todo se hace dentro de una clase genérica Operation<T>, y todo lo que tiene que hacer es asignar la operación requerida a un delegado. Me gusta add = Operation<double>.Add.

Se utiliza como esto: Código

public struct MyPoint 
{ 
    public readonly double x, y; 
    public MyPoint(double x, double y) { this.x=x; this.y=y; } 
    // User types must have defined operators 
    public static MyPoint operator+(MyPoint a, MyPoint b) 
    { 
     return new MyPoint(a.x+b.x, a.y+b.y); 
    } 
} 
class Program 
{ 
    // Sample generic method using Operation<T> 
    public static T DoubleIt<T>(T a) 
    { 
     Func<T, T, T> add=Operation<T>.Add; 
     return add(a, a); 
    } 

    // Example of using generic math 
    static void Main(string[] args) 
    { 
     var x=DoubleIt(1);    //add integers, x=2 
     var y=DoubleIt(Math.PI);  //add doubles, y=6.2831853071795862 
     MyPoint P=new MyPoint(x, y); 
     var Q=DoubleIt(P);    //add user types, Q=(4.0,12.566370614359172) 

     var s=DoubleIt("ABC");   //concatenate strings, s="ABCABC" 
    } 
} 

Operation<T> Fuente cortesía de pasta papelera: http://pastebin.com/nuqdeY8z

con la atribución a continuación:

/* Copyright (C) 2007 The Trustees of Indiana University 
* 
* Use, modification and distribution is subject to the Boost Software 
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 
* http://www.boost.org/LICENSE_1_0.txt) 
* 
* Authors: Douglas Gregor 
*   Andrew Lumsdaine 
*   
* Url:  http://www.osl.iu.edu/research/mpi.net/svn/ 
* 
* This file provides the "Operations" class, which contains common 
* reduction operations such as addition and multiplication for any 
* type. 
* 
* This code was heavily influenced by Keith Farmer's 
* Operator Overloading with Generics 
* at http://www.codeproject.com/csharp/genericoperators.asp 
* 
* All MPI related code removed by ja72. 
*/ 
+0

La respuesta superior ya describe el uso de este enfoque. – Servy

+0

Oh, solo vi la solución de palabras clave 'dynamic'. – ja72

Cuestiones relacionadas