How can I multiply a float and a generic type?

2019-03-25 11:45发布

问题:

I'm programming in Unity 3.4.2 on OS X using C#.

I have a class like the following:

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

When Unity compiles this class, it gives me this error message:

error CS0019: Operator *' cannot be applied to operands of type float' and `T'

I know that the types I provide for T will support multiplication with float. How can I implement generic multiplication in this case?

回答1:

Ahhh, good ol' Haskell.

You can't do that in C#, you should have multiple DoFoo's, one for float, one for double and one for decimal - there aren't all that many float types. You can drop the float variant, too, as it will be implicitly cast into a double anyway.



回答2:

It's not possible to do this with generics alone as they don't support operators such as +, /, -, *. To do this you'll need to introduce a layer of abstraction in the form of say an interface or a lambda to provide the operation.

For example

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

Now at construction time of Foo<T> you can tell it how to multiply with a float type

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


回答3:

In C# 4, you can use dynamic if you are confident that float * T => T.

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

Other options are:

  1. Use an expression-tree and compile it down to delegate (suitable for caching) that does the multiplication for you.
  2. Reflection - Either directly, or by producing a delegate first.
  3. Accept a delegate, as JaredPar mentions.


回答4:

Since you say dynamic is not an option: if you obtain MiscUtil, I wrote some support in there for operators on generics. In particular, look at Operator.Multiply and Operator.MultiplyAlternative, discussed here. This resolves the methods at runtime, baking them into delegates as needed.

This uses the Expression API, so will work on 3.5, but if needed I could reproduce it for 2.0 using ILGenerator



回答5:

try this

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

it should've work, no errors encountered yet...



标签: c# generics mono