Rob*_* H. 3 .net c# extension-methods boxing unboxing
我正在研究一种仅适用于引用类型的扩展方法。然而,我认为目前正在对值进行装箱和拆箱。我怎样才能避免这种情况?
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
public class Foo
{
public int Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在某种方法中:
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
Run Code Online (Sandbox Code Playgroud)
那不是拳击。你认为哪里是拳击?如果这是因为您已经查看了“==”周围的 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)
Run Code Online (Sandbox Code Playgroud)
话虽如此,如果您想将扩展方法限制为引用类型,请这样做:
public static TResult GetOrDefaultIfNull<T, TResult>
(this T obj, Func<T, TResult> getValue, TResult defaultValue)
where T : class
Run Code Online (Sandbox Code Playgroud)
IL 中仍然会有一个盒子,但不用担心 - 实际上不会发生任何盒子。毕竟,什么可以装箱呢?您提供了一个引用,并且引用本身永远不会被装箱 - 只有值类型值才会被装箱。