Как избежать бокса / распаковки при расширении системы .Object?
-
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, но не волнуйтесь - ни один бокс на самом деле не произойдет. В конце концов, что мог Будьте в штучной упаковке? Вы предоставляете ссылку, и сами ссылки никогда не будут в штучной упаковке - только значения типов ценностей в боксе.
Другие советы
Просто в этом коде нет ничего, что потребует бокса. Там являются Сценарии, в которых бокс неизбежна, и есть также дополнительные оправки для преодоления зазора между типами Value / Ref (constrained
) в некоторых случаях.
Но не в этом случае; нет действительный Требуется бокс (JIT может удалить несколько ящиков, но не все, к сожалению)