2008-09-29 7 views
30

Was würde ich tun, wenn ich eine generische Methode haben möchte, die nur Typen akzeptiert, die einen Operator überladen haben, zum Beispiel den Subtraktionsoperator. Ich habe versucht, eine Schnittstelle als Einschränkung zu verwenden, aber Interfaces können nicht überladen werden.Lösung für überladene Operatorbeschränkung in .NET-Generics

Was ist der beste Weg, dies zu erreichen?

+1

Haben Sie ein Beispiel, in dem Sie versuchen, um das zu benutzen? Ich kann nicht an etwas denken, das nützlich wäre? –

+0

Eine generische "Sum" -Methode wäre ein einfaches Beispiel. T Summe (IEnumerable Sequenz); // wo T hat '+' Operator – blackwing

+0

möglich Duplikat von [Definieren Sie eine generische, die den + Operator implementiert] (http://stackoverflow.com/questions/3598341/define-a-generic-that-implements-the-operator) – Timwi

Antwort

37

Es gibt keine sofortige Antwort; Operatoren sind statisch und können nicht in Zwangsbedingungen ausgedrückt werden - und die vorhandenen Primitiven implementieren keine spezifische Schnittstelle (Kontrast zu IComparable [<T>], der verwendet werden kann, um größer als/kleiner als zu emulieren).

Jedoch; wenn Sie nur wollen, dass es funktioniert, dann in .NET 3.5 gibt es einige Optionen ...

Ich habe zusammen eine Bibliothek here, die mit Generika effizienten und einfachen Zugang zu den Betreibern ermöglicht - wie zum Beispiel:

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

Es kann als Teil von MiscUtil

Zusätzlich in C# 4.0 heruntergeladen werden, wird dies möglich über dynamic:

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

Ich hatte auch (an einem Punkt) eine .NET 2.0 Version, aber das ist weniger getestet. Die andere Option ist eine Schnittstelle wie

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

etc, zu schaffen, aber dann müssen Sie ein ICalc<T>; durch alle Methoden zu übergeben, die chaotisch wird.

+0

Ich mag die Fähigkeit, dynamische in .NET 4.0 zu verwenden, macht es die Dinge viel einfacher. Es lohnt sich jedoch, darauf hinzuweisen, dass es bei der Verwendung eine Leistungseinbuße geben wird, da zur Laufzeit mehr Arbeit erforderlich ist. Es würde mich interessieren, wie viel Einfluss es hat, es braucht ein Benchmarking, denke ich. –

+0

Benchmark bereits erledigt; versuchen Sie den Code von hier: http://social.msdn.microsoft.com/Forums/en-US/vs2010ctpvbcs/thread/287db1b9-c135-40bc-a1c5-a8a51efbfc65 –

+0

Ich probierte Ihre Bibliothek (für .NET 3.5), und ich habe eine Frage: Warum funktioniert die folgende Zeile nicht: MiscUtil.Operator.Add ("A", "B") ;. In meinem Verständnis sollte es "AB" zurückgeben. – Malki

5

Ich fand, dass IL kann das wirklich gut damit umgehen. Ex.

ldarg.0 
ldarg.1 
add 
ret 

Kompiliert in einer generischen Methode, wird der Code ordnungsgemäß ausgeführt, solange ein primitiver Typ angegeben wird. Es kann möglich sein, dies auf Aufrufoperatorfunktionen auf nicht-primitiven Typen auszudehnen.

Siehe here.

-1

Es ist ein Stück Code gestohlen von den Internaten, dass ich eine Menge dafür verwende. Es sucht nach oder erstellt unter Verwendung von IL Grundrechenarten. Es ist alles innerhalb einer generischen Klasse Operation<T> getan, und alles, was Sie tun müssen, ist die erforderliche Operation zu einem Delegaten zuweisen. Wie add = Operation<double>.Add.

Es wird wie folgt verwendet:

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> Quellcode mit freundlicher Genehmigung von Paste ist: http://pastebin.com/nuqdeY8z

mit Zuschreibung unter:

/* 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

Die oberste Antwort beschreibt bereits die Verwendung dieses Ansatzes. – Servy

+0

Oh, ich habe nur "dynamische" Keyword-Lösung gesehen. – ja72