Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: blackwingОтветов: 3

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

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

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

genericsconstraintsoperator-overloading

Ответы

Ответ 1 · рейтинг 49 · Marc Gravell

Нет немедленного ответа; операторы статичны и не могут быть выражены в ограничениях - а существующие примитивы не реализуют какой-либо конкретный интерфейс (в отличие от 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>; через все методы, что становится беспорядочным.

Ответ 2 · рейтинг 9 · YellPika

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

ldarg.0
ldarg.1
add
ret

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

См. здесь.

Ответ 3 · рейтинг -1 · John Alexiou

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы