Подтвердить что ты не робот

С# Общие операторы

Я пытаюсь реализовать общий оператор следующим образом:

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. Я надеялся решить это с помощью общего оператора +, но я просто получил синтаксическую ошибку для вышеупомянутого (в <), заставляя меня полагать, что такой код не является законным.

Есть ли способ сделать общий оператор?

4b9b3361

Ответ 1

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

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

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

Foo x = new Bar();
Foo y = new Bar();
var z = x + y; // calls Foo.operator+;

Ответ 2

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

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

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

[System.Runtime.CompilerServices.SpecialName]
public static T op_Addition<T>(T a, T b) { ... }

Ответ 4

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

Действительно, вы даже не можете использовать операторы с generics в С#.

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

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;
}

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

Ответ 5

Я искал то же самое, и 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.