Решение для перегруженного ограничения оператора в .NET-дженериках

Что мне делать, если я хочу иметь общий метод, который принимает только типы, которые перегружали оператор, например, оператор вычитания. Я попытался использовать интерфейс в качестве ограничения, но интерфейсы не могут иметь перегрузку оператора.

Каков наилучший способ достичь этого?

Нет немедленного ответа; операторы являются статическими и не могут быть выражены в ограничениях – и существующие примитивы не реализуют какой-либо конкретный интерфейс (контраст с IComparable [], который может использоваться для эмуляции большего или меньшего).

Однако; если вы просто хотите, чтобы он работал, то в .NET 3.5 есть несколько вариантов …

Я собрал здесь библиотеку, которая обеспечивает эффективный и простой доступ к операторам с дженериками – например:

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

Его можно загрузить как часть MiscUtil

Кроме того, в C # 4.0 это становится возможным благодаря dynamic :

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

У меня также была (в какой-то момент) версия .NET 2.0, но она менее тестировалась. Другой вариант – создать интерфейс, такой как

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

и т. д., но тогда вам нужно передать ICalc; через все методы, которые становятся беспорядочными.

Я обнаружил, что IL действительно справляется с этим достаточно хорошо. Ex.

 ldarg.0 ldarg.1 add ret 

Скомпилированный в общем методе, код будет работать нормально до тех пор, пока не будет указан примитивный тип. Возможно, это можно расширить, чтобы вызвать операторские функции для не-примитивных типов.

См. Здесь .

Есть код, украденный у интернатов, который я много использую для этого. Он ищет или строит с использованием базовых арифметических операторов IL . Все это делается в classе Operation generic, и все, что вам нужно сделать, – назначить требуемую операцию в делегат. Как add = Operation.Add .

Он используется следующим образом:

 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+bx, a.y+by); } } class Program { // Sample generic method using Operation public static T DoubleIt(T a) { Func add=Operation.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 Исходный код предоставлен пастой bin: http://pastebin.com/nuqdeY8z

с указанием ниже:

 /* 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. */ 
Давайте будем гением компьютера.