繁体   English   中英

如何避免拳击值类型

[英]How to avoid boxing of value types

假设我有一些类根据传递给它的泛型类型调用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>`

我有这样的实现:

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

但是对于值类型来说性能是可怕的,因为Func<,>的内部实现引起了装箱Func<,>object作为泛型类型。

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

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

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

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

  1. 在从字典中获取T函数之前,它已注册。
  2. as cast之后它不是null

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

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

您可以使用静态通用变量来缓存解析器。 在我的快速测试中,这花费了大约三分之一的时间来执行并避免装箱。

由于ResolverCache<Func<int,int>>.Resolver是一个不同于ResolverCache<Func<string,string>>.Resolver变量ResolverCache<Func<string,string>>.Resolver ,你可以以类型安全的方式存储不同的解析器。

class Resolver
{
    static class ResolverCache<T>
    {
        public static T Resolver { get; set; }
    }

    void AddResolver<T>(T resolver)
    {
        ResolverCache<T>.Resolver = resolver;
    }

    public Resolver()
    {
        Func<int, int> intResolver = o => (int)o * (int)o;
        Func<int, int, int> intResolver2 = (o, p) => (int)o * (int)p;
        Func<string, string> stringResolver = o => (string)o + (string)o;

        AddResolver(intResolver);
        AddResolver(intResolver2);
        AddResolver(stringResolver);

        // and so on; 
    }

    public T Invoke<T>(T t1)
    {
        var resolver = ResolverCache<Func<T, T>>.Resolver ?? (v => { throw new Exception("No resolver registered."); });
        return resolver(t1);
    }

    public T Invoke<T>(T t1, T t2)
    {
        var resolver = ResolverCache<Func<T, T, T>>.Resolver ?? ((v, u) => { throw new Exception("No resolver registered."); });
        return resolver(t1, t2);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM