Comment puis-je éviter la boxe / unboxing lors de l'extension System.Object?
-
25-09-2019 - |
Question
Je travaille sur une méthode d'extension qui est uniquement applicable aux types de référence. Je pense, cependant, il est actuellement la boxe et unboxing la valeur. Comment puis-je éviter cela?
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);
}
}
}
Exemple d'utilisation:
public class Foo
{
public int Bar { get; set; }
}
Dans une méthode:
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
La solution
Ce n'est pas la boxe. Où pensez-vous qu'il est la boxe? Si c'est parce que vous avez regardé l'IL autour de « == », ne le laissez pas vous tromper - le JIT va décider ce qu'il faut faire ici. Il a la possibilité de générer du code natif différent pour chaque couple (T
, TResult
). En fait, le code sera partagé pour tous les types de référence, et diffèrent pour les types de valeur. Donc, vous finiriez avec:
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)
Cela dit, si vous voulez limiter votre méthode d'extension à des types de référence, faire:
public static TResult GetOrDefaultIfNull<T, TResult>
(this T obj, Func<T, TResult> getValue, TResult defaultValue)
where T : class
Il y aura toujours une boîte à l'IL, mais ne vous inquiétez pas - pas la boxe va effectivement se produire. Après tout, ce que pourrait être acculé? Vous fournissez une référence, et les références ne sont jamais eux-mêmes en boîte -. Seules les valeurs de type valeur sont mis en boîte
Autres conseils
Simplement, il n'y a rien dans ce code qui nécessiterait la boxe. Il sont scénarios où la boxe est inévitable, et il y a aussi opcodes supplémentaires pour combler l'écart entre les types valeur / ref ( constrained
) dans certains cas.
Mais pas dans ce cas; pas réelle boxe nécessaire (le JIT peut enlever quelques cas de boîte - mais pas tous, malheureusement)