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

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

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

4 ответа

Решение

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

Тем не мение; если вы просто хотите, чтобы это работало, то в.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>; через все методы, которые становятся грязными.

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

ldarg.0
ldarg.1
add
ret

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

Смотрите здесь.

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

      public class Example
{
    public static T Add<T>(T left, T right, Func<T, T, T> addFunc) =>
        addFunc(left, right);
}

Определите метод, который принимает делегат в качестве параметра, и используйте его следующим образом.

      var result = Example.Add(10, 20, (x, y) => x + y);

Есть фрагмент кода, украденный из интернатов, который я часто использую для этого. Он ищет или строит используя 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> Исходный код любезно предоставлен вставкой 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. 
 */
Другие вопросы по тегам