如何避免拳击值类型

jdp*_*nix 3 c# generics boxing

假设我有一些类Func根据传递给它的泛型类型调用一个,我有一个类所需的公共接口:

var r = new Resolver(); 
var i = r.Invoke(10); // invokes some function `Func<int,int>`
var j = r.Invoke("Hello"); // Same, but `Func<string,string>`
var k = r.Invoke(10, 10); // Same but 'Func<int,int,int>`
Run Code Online (Sandbox Code Playgroud)

我有这样的实现:

class Resolver {
    readonly IDictionary<Type, Func<object, object>> _funcs = new Dictionary<Type, Func<object, object>>();

    public Resolver() {
        _funcs.Add(typeof(int), o => (int)o*(int)o);
        _funcs.Add(typeof(string), o => (string)o + (string)o);
        // and so on; 
    }

    public T Invoke<T>(T t1) {
        return (T) _funcs[typeof (T)](t1);
    }

    public T Invoke<T>(T t1, T t2) {
        return (T)_funcs[typeof(T)](t1);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是对于值类型来说性能是可怕的,因为由于Func<,>具有object泛型类型的内部实现而引起的装箱.

有没有办法实现我想要的公共接口,避免拳击值类型?我也不介意实现中的静态类型安全,但可以没有.

Ale*_*lex 5

你可以做以下简单的技巧(不比你当前的实现更安全或更不安全):

class Resolver
{
    readonly IDictionary<Type, object> _unaryFuncs = new Dictionary<Type, object>();
    readonly IDictionary<Type, object> _binaryFuncs = new Dictionary<Type, object>();

    public Resolver()
    {
        _unaryFuncs.Add(typeof(int),  new Func<int, int>(o => o * o));
        _unaryFuncs.Add(typeof(string), new Func<string, string(o => o + o));
        _binaryFuncs.Add(typeof(int), new Func<int, int, int>((x, y) => x + y));
        // and so on; 
    }

    public T Invoke<T>(T t1)
    {
        var f = _unaryFuncs[typeof(T)] as Func<T, T>;
        return f(t1);
    }

    public T Invoke<T>(T t1, T t2)
    {
        var f = _binaryFuncs[typeof(T)] as Func<T, T, T>;
        return f(t1, t2);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能想要添加一些错误检查,如检查

  1. 一个T函数是从字典中得到它之前注册.
  2. 演员null之后不是as.

并添加类型安全注册功能:

public void Register<T>(Func<T, T> unaryFunc)
{
    _unaryFuncs[typeof(T)] = unaryFunc;
}

public void Register<T>(Func<T, T, T> binaryFunc)
{
    _binaryFuncs[typeof(T)] = binaryFunc;
}
Run Code Online (Sandbox Code Playgroud)