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

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

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

У вас есть пример того, где вы пытаетесь это использовать? Я не могу придумать ничего, что было бы полезно?

Mitch Wheat 29.09.2008 09:40

Простой пример - универсальный метод «Sum». T Sum <T> (последовательность IEnumerable <T>); // где T имеет оператор '+'

blackwing 29.09.2008 12:11

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

Timwi 03.09.2010 17:11

Как вы обнаружили, просто невозможно определить статический метод в интерфейсе, поэтому вы не можете использовать его в качестве ограничения для вашего универсального метода. Вот несколько сложный обходной путь: codeproject.com/KB/cs/genericnumerics.aspx Если вы используете .NET 3.5, это также можно сделать с помощью деревьев выражений LINQ, как показано ниже: rogeralsing.com/2008/02/27/…

Ben Hoffstein 29.09.2008 09:45

Обратите внимание, что в блоге Роджера мы обсуждаем / сравниваем две реализации (они очень похожи) - и делается вывод, что код MiscUtil (ссылка на который приведена ранее) более развита. Но они используют тот же фундаментальный подход.

Marc Gravell 29.09.2008 23:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
35
5
17 152
3
Перейти к ответу Данный вопрос помечен как решенный

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

Мне нравится возможность использовать динамический код в .NET 4.0, это, безусловно, значительно упрощает работу. Однако стоит отметить, что его использование повлияет на производительность, потому что он должен выполнять больше работы во время выполнения. Мне было бы интересно узнать, какое влияние это оказывает, я думаю, это требует некоторого сравнительного анализа.

Martin Sherburn 28.07.2009 20:23

Тест уже выполнен; попробуйте код отсюда: social.msdn.microsoft.com/Forums/en-US/vs2010ctpvbcs/thread/‌…

Marc Gravell 29.07.2009 01:11

Я пробовал вашу библиотеку (для .NET 3.5), и у меня есть вопрос: почему не работает следующая строка: MiscUtil.Operator.Add ("A", "B") ;. В моем понимании он должен вернуть "AB".

Malki 03.09.2010 20:24

@Malki - ну, мы мог добавляем это, но на самом деле это не арифметическая операция. И, строго говоря, на самом деле это не определенный оператор - в настоящее время это компилятор (а не сам тип), который обеспечивает значение + для строк ...

Marc Gravell 06.09.2010 09:16

Есть ли смысл использовать дженерики, если они будут преобразованы в динамические? Почему бы просто не сделать параметры и код возврата динамическими? Есть ли преимущество в таком смешивании дженериков и динамиков?

9a3eedi 20.11.2014 11:26

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

ldarg.0
ldarg.1
add
ret

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

См. здесь.

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

О, я видел только решение ключевого слова dynamic.

John Alexiou 18.08.2015 17:23

Другие вопросы по теме