C # Универсальные операторы - PullRequest
20 голосов
/ 06 мая 2011

Я пытаюсь реализовать универсальный оператор, например, так:

class Foo
{
   public static T operator +<T>(T a, T b) 
   {
       // Do something with a and b that makes sense for operator + here
   }
}

На самом деле я пытаюсь изящно обрабатывать наследование. Со стандартным оператором + в Foo, где T вместо «Foo», если кто-то является производным от Foo (скажем, Bar наследует Foo), то операция Bar + Bar все равно будет возвращать Foo. Я надеялся решить эту проблему с помощью универсального оператора +, но я только что получил синтаксическую ошибку для вышеуказанного (в <), заставив меня поверить, что такой код недопустим. </p>

Есть ли способ сделать универсальный оператор?

Ответы [ 5 ]

17 голосов
/ 06 мая 2011

Нет, вы не можете объявлять универсальные операторы в C #.

Операторы и наследование не очень хорошо сочетаются.

Если вы хотите, чтобы Foo + Foo возвращала Foo, а Bar + Bar возвращала Bar, вам необходимо определить один оператор для каждого класса. Но, поскольку операторы статичны, вы не получите преимуществ полиморфизма, потому что какой оператор вызывать, будет решено во время компиляции:

Foo x = new Bar();
Foo y = new Bar();
var z = x + y; // calls Foo.operator+;
6 голосов
/ 25 марта 2014

https://jonskeet.uk/csharp/miscutil/usage/genericoperators.html

static T Add<T>(T a, T b) {
    //TODO: re-use delegate!
    // declare the parameters
    ParameterExpression paramA = Expression.Parameter(typeof(T), "a"),
        paramB = Expression.Parameter(typeof(T), "b");
    // add the parameters together
    BinaryExpression body = Expression.Add(paramA, paramB);
    // compile it
    Func<T, T, T> add = Expression.Lambda<Func<T, T, T>>(body, paramA, paramB).Compile();
    // call it
    return add(a,b);       
}
3 голосов
/ 10 октября 2012

Вы можете просто определить оператор в универсальном классе Foo.

Вы также можете создавать реальные универсальные операторы, но компилятор C # не будет их использовать.

[System.Runtime.CompilerServices.SpecialName]
public static T op_Addition<T>(T a, T b) { ... }
2 голосов
/ 06 мая 2011

Вы не можете объявлять универсальные операторы в C # - я не уверен в рассуждениях, но предполагаю, что это полезная вещь по сравнению с усилиями для команды разработчиков (я думаю, что здесь может быть пост, где Джон Скит будет обсуждать его, или, возможно, на егоблог, когда он обсуждал вещи, которые он хотел бы видеть в C #).

Действительно, вы даже не можете использовать операторы с обобщениями в C #.

Это потому, что обобщенные элементы должныбыть применимыми для всех возможных типов, которые могут быть предоставлены.Вот почему вы должны использовать универсальный тип для классов, когда вы хотите использовать ==, как показано ниже:

void IsEqual<T>(T x, T y) where T : class
{
    return x == y;
}

К сожалению, вы не можете сделать:

void Add<T>(T x, T y)  where T : operator +
{
    return x + y;
}

Вас также может заинтересоватьв этой краткой сводной статье я наткнулся.

0 голосов
/ 22 марта 2015

Искал то же самое, и Google привел меня сюда .... Я не был слишком доволен принятым ответом и искал обходной путь.

Мне удалось реализовать это с помощью обобщений.Вот класс Foo и Bar:

    class Foo
    {
        private int value;

        public Foo(int x)
        {
            value = x;
        }
        public virtual int getVal()
        {
            return value;
        }
    }

    class Bar : Foo
    {
        private int derivedValue;

        public Bar(int x):base(x) 
        {
            derivedValue = x;
        }
        public override int getVal()
        {
            return derivedValue;
        }
    }

Затем универсальный класс, содержащий операторы, но ограниченный типом Foo и производный от Foo:

    class GenericOp<T> where T : Foo
    {
        private T value;

        public GenericOp(T x)
        {
            value = x;
        }
        public static Foo operator +(GenericOp<T> a, GenericOp<T> b) 
        {
            return new Foo(a.value.getVal() + b.value.getVal());
        }
    }

Некоторый код использования, показывающий вам всегдавернуть Foo, а также мешает вам смешивать типы:

Foo f1 = new Foo(1);
Foo f2 = new Foo(2);
Bar b1 = new Bar(10);
Bar b2 = new Bar(20);

GenericOp<Foo> left = new GenericOp<Foo>(f1);
GenericOp<Foo> right = new GenericOp<Foo>(f2);
Foo res = left + right;

GenericOp<Bar> left1 = new GenericOp<Bar>(b1);
GenericOp<Bar> right1 = new GenericOp<Bar>(b2);
Foo res1 = left1 + right1;

GenericOp<Foo> left2 = new GenericOp<Foo>(f1);
GenericOp<Bar> right2 = new GenericOp<Bar>(b1);
//Foo res2 = left2 + right2; //this fails and rightfully so.
...