Como evito o boxe/unboxing ao estender o sistema.Object?
-
25-09-2019 - |
Pergunta
Estou trabalhando em um método de extensão aplicável apenas aos tipos de referência. Eu acho que, no entanto, está atualmente boxe e dividindo o valor. Como posso evitar isso?
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);
}
}
}
Exemplo de uso:
public class Foo
{
public int Bar { get; set; }
}
Em algum método:
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
Solução
Isso não é boxe. Onde você acha isso é boxe? Se é porque você olhou para o IL em torno de "==", não deixe isso enganar você - o jit decide o que fazer aqui. Tem a chance de gerar código nativo diferente para cada um (T
, TResult
) par. De fato, o código será compartilhado para todos os tipos de referência e difere para os tipos de valor. Então você acabaria com:
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)
Dito isto, se você deseja restringir seu método de extensão aos tipos de referência, faça -o:
public static TResult GetOrDefaultIfNull<T, TResult>
(this T obj, Func<T, TResult> getValue, TResult defaultValue)
where T : class
Ainda haverá uma caixa na IL, mas não se preocupe - nenhum boxe realmente ocorrerá. Afinal, o que poderia estar em caixa? Você está fornecendo uma referência e as próprias referências nunca são encaixotadas - apenas os valores do tipo de valor são encaixotados.
Outras dicas
Simplesmente, não há nada nesse código que exigiria boxe. Lá são Cenários em que o boxe é inevitável e também existem códigos opciais adicionais para a ponte da lacuna entre os tipos de valor/ref (constrained
) em alguns casos.
Mas não neste caso; não real O boxe necessário (o JIT pode remover alguns estojos em forma de caixa - mas não tudo, infelizmente)