3

私は参照型にのみ適用できる拡張メソッドに取り組んでいます。ただし、現在は値のボックス化とボックス化解除を行っていると思います。どうすればこれを回避できますか?

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
4

2 に答える 2

5

それはボクシングではありません。ボクシングどこだと思いますか?「==」の周りの 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 にはまだボックスがありますが、心配しないでください。実際にボックス化は行われません。参照を提供しており、参照自体がボックス化されることはありません。値型の値のみがボックス化されます。

于 2010-04-09T16:31:27.893 に答える
2

簡単に言えば、そのコードにはボクシングを必要とするものは何もありません。ボックス化が避けられないシナリオがあり、場合によっては、値/参照型 ( ) 間のギャップを埋めるための追加のオペコードもありconstrainedます。

しかし、この場合はそうではありません。実際のボックス化は必要ありません(JIT はいくつかのボックスのようなケースを削除できますが、残念ながらすべてではありません)

于 2010-04-09T16:39:20.720 に答える