Как я могу умножить float и общий тип?

Я программирую Unity 3.4.2 на OS X с помощью С#.

У меня есть класс вроде следующего:

class Foo<T>
{
    public T DoFoo(T bar)
    {
        float aFloatValue = 1.0f;
        // Do other stuff...
        return aFloatValue * bar;
    }
}

Когда Unity компилирует этот класс, он дает мне это сообщение об ошибке:

ошибка CS0019: Оператор *' cannot be applied to operands of type float 'и `T'

Я знаю, что типы, которые я предоставляю для T, будут поддерживать умножение с помощью float. Как я могу реализовать обобщенное умножение в этом случае?

Ответ 1

Ahhh, хороший ol 'Haskell.

Вы не можете сделать это на С#, у вас должно быть несколько DoFoo, одно для float, одно для double и one для десятичного числа - там не так много типов float. Вы также можете оставить вариант с плавающей запятой, так как он будет неявно переброшен в double.

Ответ 2

Это невозможно сделать с помощью генериков, поскольку они не поддерживают такие операторы, как +, /, -, *. Для этого вам нужно ввести слой абстракции в форме, например, интерфейса или лямбда, чтобы обеспечить операцию.

Например

class Foo<T> {
  Func<T, float, T> _multiplyFunc;
  public Foo(Func<T, float, T> multiplyFunc) {
    _multiplyFunc = multiplyFunc;
  }
  public T DoFoo(T bar) {
    float aFloatValue = 1.0f;
    return _multiplyFunc(bar, aFloatValue);
  }
}

Теперь при времени построения Foo<T> вы можете сказать, как умножить его на тип float

var f = new Foo<MyType>((x, y) => x * y);

Ответ 3

В С# 4 вы можете использовать dynamic, если вы уверены, что float * T => T.

class Foo<T>
{
    public T DoFoo(T bar)
    {
        dynamic aFloatValue = 1.0f;
        // Do other stuff...
        return aFloatValue * bar;
    }
}

Другие варианты:

  • Используйте дерево выражений и скомпилируйте его для делегирования (подходящего для кэширования), который выполняет умножение для вас.
  • Отражение - либо непосредственно, либо сначала создавая делегат.
  • Принять делегата, как упоминает JaredPar.

Ответ 4

Поскольку вы говорите, что dynamic не вариант: если вы получаете MiscUtil, я написал некоторую поддержку там для операторов по дженерикам, В частности, посмотрите Operator.Multiply и Operator.MultiplyAlternative, обсужденные здесь здесь. Это разрешает методы во время выполнения, при необходимости выкладывая их в делегаты.

В нем используется Expression API, поэтому он будет работать на 3.5, но при необходимости я могу воспроизвести его для 2.0, используя ILGenerator

Ответ 5

попробуйте это

class Foo<T>
{
    public T DoFoo(T bar)
    {
        float aFloatValue = 1.0f;
        var barValue = bar as dynamic;
        return aFloatValue * bar;
    }
}

он должен работать, ошибок еще не встречалось...