Что бы я сделал, если бы я хотел иметь общий метод, который принимает только те типы, которые перегружают оператор, например оператор вычитания. Я пробовал использовать интерфейс в качестве ограничения, но интерфейсы не могут иметь перегрузку оператора.
Как лучше всего этого добиться?
Простой пример - универсальный метод «Sum». T Sum <T> (последовательность IEnumerable <T>); // где T имеет оператор '+'
возможный дубликат Определите универсальный, реализующий оператор +
Как вы обнаружили, просто невозможно определить статический метод в интерфейсе, поэтому вы не можете использовать его в качестве ограничения для вашего универсального метода. Вот несколько сложный обходной путь: codeproject.com/KB/cs/genericnumerics.aspx Если вы используете .NET 3.5, это также можно сделать с помощью деревьев выражений LINQ, как показано ниже: rogeralsing.com/2008/02/27/…
Обратите внимание, что в блоге Роджера мы обсуждаем / сравниваем две реализации (они очень похожи) - и делается вывод, что код MiscUtil (ссылка на который приведена ранее) более развита. Но они используют тот же фундаментальный подход.





Нет немедленного ответа; операторы статичны и не могут быть выражены в ограничениях, а существующие примитивы не реализуют какой-либо конкретный интерфейс (в отличие от 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, это, безусловно, значительно упрощает работу. Однако стоит отметить, что его использование повлияет на производительность, потому что он должен выполнять больше работы во время выполнения. Мне было бы интересно узнать, какое влияние это оказывает, я думаю, это требует некоторого сравнительного анализа.
Тест уже выполнен; попробуйте код отсюда: social.msdn.microsoft.com/Forums/en-US/vs2010ctpvbcs/thread/…
Я пробовал вашу библиотеку (для .NET 3.5), и у меня есть вопрос: почему не работает следующая строка: MiscUtil.Operator.Add ("A", "B") ;. В моем понимании он должен вернуть "AB".
@Malki - ну, мы мог добавляем это, но на самом деле это не арифметическая операция. И, строго говоря, на самом деле это не определенный оператор - в настоящее время это компилятор (а не сам тип), который обеспечивает значение + для строк ...
Есть ли смысл использовать дженерики, если они будут преобразованы в динамические? Почему бы просто не сделать параметры и код возврата динамическими? Есть ли преимущество в таком смешивании дженериков и динамиков?
Я обнаружил, что 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.
У вас есть пример того, где вы пытаетесь это использовать? Я не могу придумать ничего, что было бы полезно?