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

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

Как лучше всего этого добиться?


person blackwing    schedule 29.09.2008    source источник
comment
У вас есть пример того, где вы пытаетесь это использовать? Я не могу придумать ничего, что было бы полезно?   -  person Mitch Wheat    schedule 29.09.2008
comment
Как вы обнаружили, просто невозможно определить статический метод в интерфейсе, поэтому вы не можете использовать его в качестве ограничения для вашего универсального метода. Вот несколько сложный обходной путь: codeproject.com/KB/cs/genericnumerics.aspx Если вы используете .NET 3.5, это также можно сделать с помощью деревьев выражений LINQ, как показано ниже: rogeralsing.com/2008/02/27/   -  person Ben Hoffstein    schedule 29.09.2008
comment
Простой пример - универсальный метод Sum. T Sum ‹T› (IEnumerable ‹T› последовательность); // где T имеет оператор '+'   -  person blackwing    schedule 29.09.2008
comment
Обратите внимание, что в блоге Роджера мы обсуждаем / противопоставляем две реализации (они очень похожи) - с выводом, что код MiscUtil (связанный ранее) более развит. Но они используют тот же фундаментальный подход.   -  person Marc Gravell    schedule 29.09.2008
comment
возможный дубликат Определите общий тип, реализующий оператор +   -  person Timwi    schedule 03.09.2010


Ответы (3)


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

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

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

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

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

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

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

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

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

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

person Marc Gravell    schedule 29.09.2008
comment
Мне нравится возможность использовать динамический код в .NET 4.0, это значительно упрощает работу. Однако стоит отметить, что при его использовании будет снижаться производительность, потому что он должен выполнять больше работы во время выполнения. Мне было бы интересно узнать, насколько это повлияет, я думаю, это требует некоторого тестирования. - person Martin Sherburn; 28.07.2009
comment
Тест уже выполнен; попробуйте код отсюда: social.msdn.microsoft.com/Forums/en-US/vs2010ctpvbcs/thread/ - person Marc Gravell; 29.07.2009
comment
Я попробовал вашу библиотеку (для .NET 3.5), и у меня есть вопрос: почему не работает следующая строка: MiscUtil.Operator.Add (A, B) ;. В моем понимании он должен вернуть AB. - person Malki; 03.09.2010
comment
@Malki - ну, мы могли добавить это, но на самом деле это не арифметическая операция. И, строго говоря, на самом деле это не определенный оператор - в настоящее время это компилятор (а не сам тип), который обеспечивает это значение + для строк ... - person Marc Gravell; 06.09.2010
comment
Есть ли смысл использовать дженерики, если они будут преобразованы в динамические? Почему бы просто не сделать параметры и код возврата динамическими? Есть ли преимущество в таком смешивании дженериков и динамиков? - person 9a3eedi; 20.11.2014

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

ldarg.0
ldarg.1
add
ret

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

См. здесь.

person YellPika    schedule 26.06.2011

У интерната украден фрагмент кода, который я часто использую для этого. Он ищет или строит с использованием IL базовых арифметических операторов. Все это делается в Operation<T> универсальном классе, и все, что вам нужно сделать, это назначить требуемую операцию делегату. Вроде add = Operation<double>.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+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> Исходный код предоставлен корзиной для вставки: 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. 
 */
person John Alexiou    schedule 18.08.2015
comment
О, я видел только dynamic ключевое слово. - person John Alexiou; 18.08.2015