2008-09-29 11 views
30

Co zrobić, jeśli chcę mieć ogólną metodę, która akceptuje tylko typy przeciążone przez operatora, na przykład operatora odejmowania. Próbowałem używać interfejsu jako ograniczenia, ale interfejsy nie mogą przeciążać operatora.Rozwiązanie dla przeciążonego ograniczenia operatora w .NET generics

Jaki jest najlepszy sposób, aby to osiągnąć?

+1

masz przykład gdzie próbujesz korzystać z tego? Nie mogę wymyślić gdziekolwiek, co byłoby przydatne? –

+0

Ogólna metoda "Sum" byłaby prostym przykładem. T Sum (IEnumerable sekwencji); // gdzie T ma operatora "+" – blackwing

+0

możliwy duplikat [Zdefiniuj ogólny, który implementuje operator +] (http://stackoverflow.com/questions/3598341/define-a-eneric-that-implements-the-operator) – Timwi

Odpowiedz

37

Nie ma natychmiastowej odpowiedzi; operatory są statyczne i nie mogą być wyrażone w ograniczeniach - a istniejące prymitywy nie implementują żadnego konkretnego interfejsu (w przeciwieństwie do IComparable [<T>], który może być użyty do emulacji większego niż/mniejszy niż).

Jednak; jeśli po prostu chcesz go do pracy, to w .NET 3.5 istnieje kilka opcji ...

mam połączyć bibliotekę here który umożliwia wydajne i prosty dostęp do operatorów z rodzajowych - takich jak:

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

to można pobrać jako część MiscUtil

Ponadto w C# 4.0, to staje się możliwe poprzez dynamic:

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

Posiadałem również (w pewnym momencie) wersję .NET 2.0, ale jest to mniej testowane. Inną opcją jest stworzenie interfejsu takiego jak

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

etc, ale wtedy trzeba zdać ICalc<T>; przez wszystkich metod, które dostaje bałagan.

+0

Podoba mi się możliwość używania dynamicznego w .NET 4.0, to na pewno znacznie ułatwia. Warto jednak podkreślić, że będzie to implikacja wydajności, ponieważ musi on wykonywać więcej pracy w środowisku wykonawczym. Byłbym zainteresowany, aby dowiedzieć się, jak duży wpływ ma to, że potrzebuje pewnych testów porównawczych, myślę. –

+0

Benchmark już wykonano; wypróbuj kod z: http://social.msdn.microsoft.com/Forums/en-US/vs2010ctpvbcs/thread/287db1b9-c135-40bc-a1c5-a8a51efbfc65 –

+0

Wypróbowałem Twoją bibliotekę (dla .NET 3.5), i mam pytanie: dlaczego nie działa następująca linia: MiscUtil.Operator.Add ("A", "B") ;. W moim rozumieniu powinien powrócić "AB". – Malki

5

Stwierdziłem, że IL może całkiem dobrze sobie z tym poradzić. Dawny.

ldarg.0 
ldarg.1 
add 
ret 

Skompilowany w sposób ogólny kod będzie działał poprawnie tak długo, jak długo określony jest typ pierwotny. Może być możliwe rozszerzenie tego, aby wywołać funkcje operatora na typach niepochodzących.

Zobacz here.

-1

Jest kawałek kodu skradzionego z internatów, którego często używam do tego. Poszukuje lub buduje przy użyciu podstawowych operatorów arytmetycznych. Wszystko odbywa się w ramach ogólnej klasy Operation<T>, a wszystko, co musisz zrobić, to przypisać wymaganą operację do delegata. Podobnie jak add = Operation<double>.Add.

Jest on stosowany tak: Kod

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> Źródło uprzejmości pasty BIN: http://pastebin.com/nuqdeY8z

z przypisania poniżej:

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

Główna odpowiedź już opisuje użycie tego podejścia. – Servy

+0

Och, widziałem tylko "dynamiczne" rozwiązanie słów kluczowych. – ja72

Powiązane problemy