我该如何避免拳/拆箱,当延伸系统。对象?
-
25-09-2019 - |
题
我正在扩展的方法,只适用于参照类型。我认为,然而,它目前是拳击和拆箱的价值。我如何可以避免这种情况?
namespace System
{
public static class SystemExtensions
{
public static TResult GetOrDefaultIfNull<T, TResult>(this T obj, Func<T, TResult> getValue, TResult defaultValue)
{
if (obj == null)
return defaultValue;
return getValue(obj);
}
}
}
例的使用情况:
public class Foo
{
public int Bar { get; set; }
}
在一些方法:
Foo aFooObject = new Foo { Bar = 1 };
Foo nullReference = null;
Console.WriteLine(aFooObject.GetOrDefaultIfNull((o) => o.Bar, 0)); // results: 1
Console.WriteLine(nullReference.GetOrDefaultIfNull((o) => o.Bar, 0)); // results: 0
解决方案
这不是拳击。当你认为它的为的拳击?如果是因为你已经看过了IL围绕“==”,不要让它愚弄你 - JIT变来决定在这里做什么。它具有产生不同的本机代码对于每个(T
,TResult
)一对的机会。实际上,代码将所有引用类型共享,并且值类型不同。所以,你会结束:
T = string, TResult = int (native code #1)
T = Stream, TResult = byte (native code #2)
T = string, TResult = byte (native code #2)
T = Stream, TResult = string (native code #3)
说了这么多,如果你想限制你的扩展方法来引用类型,这样做的:
public static TResult GetOrDefaultIfNull<T, TResult>
(this T obj, Func<T, TResult> getValue, TResult defaultValue)
where T : class
有仍然会处于一个IL框,但不要担心 - 实际上不会发生拳。毕竟,什么的可能的加框?你提供参考,而自己从来没有盒装的引用 - 只有值类型的值被装箱
其他提示
简单地说,没有什么代码,将需要拳击。还有 都 方案的拳击是不可避免的,也有额外的操作码为之间的差距值/ref类型(constrained
)在某些情况下。
但不是在这种情况;没有 实际 拳击所需要(JIT可以删除的几个箱状的情况下-但并不是所有的,可悲的是)
不隶属于 StackOverflow