Domanda

Cosa farei se volessi avere un metodo generico che accetta solo tipi che hanno sovraccaricato un operatore, ad esempio l'operatore di sottrazione. Ho provato a utilizzare un'interfaccia come vincolo ma le interfacce non possono avere un sovraccarico dell'operatore.

Qual è il modo migliore per raggiungere questo obiettivo?

È stato utile?

Soluzione

Non c'è una risposta immediata; gli operatori sono statici e non possono essere espressi in vincoli - e le primitive esistenti non implementano alcuna interfaccia specifica (contrasto con IComparable [< T >] che può essere usata per emulare maggiore / minore -than).

Tuttavia; se vuoi solo che funzioni, allora in .NET 3.5 ci sono alcune opzioni ...

Ho messo insieme una libreria qui che consente un'efficienza e un accesso semplice agli operatori con generici, come ad esempio:

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

Può essere scaricato come parte di MiscUtil

Inoltre, in C # 4.0, questo diventa possibile tramite dynamic:

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

Avevo anche (a un certo punto) una versione .NET 2.0, ma meno testata. L'altra opzione è quella di creare un'interfaccia come

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

ecc., ma poi devi passare un ICalc<T>; attraverso tutti i metodi, che diventa disordinato.

Altri suggerimenti

Ho scoperto che IL può davvero gestirlo abbastanza bene. Ex.

ldarg.0
ldarg.1
add
ret

Compilato in un metodo generico, il codice funzionerà correttamente fino a quando viene specificato un tipo primitivo. Potrebbe essere possibile estenderlo per chiamare le funzioni dell'operatore su tipi non primitivi.

Vedi qui .

C'è un pezzo di codice rubato agli internati che uso molto per questo. Cerca o costruisce utilizzando IL operatori aritmetici di base. Viene eseguito tutto all'interno di una Operation<T> classe generica e tutto ciò che devi fare è assegnare l'operazione richiesta a un delegato. Mi piace add = Operation<double>.Add.

Viene utilizzato in questo modo:

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"
    }
}

<=> Codice sorgente per gentile concessione del cestino: http://pastebin.com/nuqdeY8z

con attribuzione di seguito:

/* 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. 
 */
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top