c# - 扩展 System.Object 时如何避免装箱/拆箱?

标签 c# .net 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);
        }
    }
}

示例用法:

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) 对生成不同的 native 代码。事实上,代码将对所有引用类型共享,而对值类型则不同。所以你最终会得到:

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 中仍然会有一个盒子,但别担心 - 实际上不会发生装箱。毕竟,什么可以装箱?您提供的是引用,而引用本身永远不会装箱 - 只有值类型的值才会装箱。

关于c# - 扩展 System.Object 时如何避免装箱/拆箱?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2609054/

相关文章:

c# - 连接和析取辅助类

c# - 如何计算 C# 中的类属性?

c# - ITextSharp 一起使用多种字体样式。即粗体、下划线、斜体...等

c# - 我可以停止 IIS 吗?

c# - 在 c# 中通过拨号调制解调器在没有互联网的情况下连接两台计算机

c# - 扩展方法与助手类

c# - Thread.MemoryBarrier 和简单属性的锁区别

c# - 异步/等待和任务

.net - 如何在页面加载前执行 Javascript 函数?

c# - 如何修改一个简单的字符串扩展来支持 SQL