Как избежать бокса / распаковки при расширении системы .Object?

StackOverflow https://stackoverflow.com/questions/2609054

Вопрос

Я работаю над методом расширения, который только применим к типом ссылок. Я думаю, однако, в настоящее время он в настоящее время бокс и распаковка значения. Как я могу избежать этого?

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, но не волнуйтесь - ни один бокс на самом деле не произойдет. В конце концов, что мог Будьте в штучной упаковке? Вы предоставляете ссылку, и сами ссылки никогда не будут в штучной упаковке - только значения типов ценностей в боксе.

Другие советы

Просто в этом коде нет ничего, что потребует бокса. Там являются Сценарии, в которых бокс неизбежна, и есть также дополнительные оправки для преодоления зазора между типами Value / Ref (constrained) в некоторых случаях.

Но не в этом случае; нет действительный Требуется бокс (JIT может удалить несколько ящиков, но не все, к сожалению)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top