[英]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);
}
}
您可能想要添加一些错误检查,如检查
T
函数之前,它已注册。 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.