lazy c# ejemplos
Propiedad en caché vs Lazy<T> (7)
Bueno, si su rendimiento es aproximadamente el mismo, la única razón para usar Lazy<T>
sobre la versión en caché sería si no está seguro de si el usuario realmente va a cargar la propiedad.
El objetivo de Lazy<T>
es esperar hasta que el usuario necesite el recurso y luego crearlo en esa instancia a tiempo. Si siempre van a necesitar recursos, entonces no tiene sentido usar Lazy<T>
, a menos que necesite algunos de sus otros propósitos, como que es seguro para subprocesos.
En .NET 4, el siguiente fragmento con una propiedad en caché también se puede escribir utilizando la clase System.Lazy<T>
. Medí el rendimiento de ambos enfoques y es prácticamente lo mismo. ¿Hay algún beneficio real o mágico de por qué debería usar uno sobre el otro?
Propiedad en caché
public static class Brushes
{
private static LinearGradientBrush _myBrush;
public static LinearGradientBrush MyBrush
{
get
{
if (_myBrush == null)
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
_myBrush = linearGradientBrush;
}
return _myBrush;
}
}
}
Lazy <T>
public static class Brushes
{
private static readonly Lazy<LinearGradientBrush> _myBrush =
new Lazy<LinearGradientBrush>(() =>
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
return linearGradientBrush;
}
);
public static LinearGradientBrush MyBrush
{
get { return _myBrush.Value; }
}
}
Lazy tiene algunos gastos generales de sincronización para proporcionar seguridad de subprocesos, mientras que la propiedad en caché se inicia por CLR antes que cualquier otro código y no es necesario pagar el costo de sincronización
Desde un punto de vista de la capacidad de prueba, Lazy está bien probado y probado artefacto.
Sin embargo, tiene una muy ligera sobrecarga, en mi opinión, sobre otra opción
Normalmente, la única razón para no utilizar lazy es restablecer la variable a nulo, por lo que el siguiente acceso hace que se cargue nuevamente. Lazy no tiene reinicio y tendrías que recrear el perezoso desde cero.
Usa Lazy<T>
, ya que expresa exactamente lo que estás haciendo: carga lenta.
Además, mantiene su propiedad muy limpia y segura para hilos.
Yo usaría Lazy<T>
en general:
- Es seguro para subprocesos (puede no ser un problema en este caso, pero lo sería en otros)
- Hace obvio lo que está pasando solo por el nombre
- Permite que null sea un valor válido
Tenga en cuenta que no tiene que usar una expresión lambda para el delegado. Por ejemplo, aquí hay un enfoque que puede ser un poco más limpio:
public static class Brushes
{
private static readonly Lazy<LinearGradientBrush> _myBrush =
new Lazy<LinearGradientBrush>(CreateMyBrush);
private static LinearGradientBrush CreateMyBrush()
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
return linearGradientBrush;
}
public static LinearGradientBrush MyBrush
{
get { return _myBrush.Value; }
}
}
Esto es particularmente útil cuando el proceso de creación se complica con bucles, etc. Tenga en cuenta que, por lo que se ve, podría usar un inicializador de colecciones para GradientStops
en su código de creación.
Otra opción es no hacer esto de forma perezosa, por supuesto ... a menos que tenga varias propiedades de ese tipo en su clase y solo desee crear los objetos relevantes de forma individualizada, puede confiar en la inicialización de la clase perezosa para muchos situaciones
Como se señala en la respuesta de DoubleDown, no hay forma de restablecer esto para forzar el recálculo (a menos que haga que el campo Lazy<T>
no sea de solo lectura), pero raramente he encontrado que sea importante.
Lazy<T>
es más simple: expresa claramente la intención del código.
También es seguro para subprocesos.
Tenga en cuenta que si realmente está utilizando esto en varios hilos, debe hacerlo [ThreadStatic]
; Los objetos GDI + no pueden compartirse entre subprocesos.
Lazy<T>
manejará correctamente los escenarios concurrentes (si pasa el LazyThreadSafetyMode correcto) mientras que su ejemplo no tiene ninguna verificación de seguridad de hilos.