C ª#,
¿Hay alguna manera de convertir una propiedad automática en una propiedad automática de carga diferida con un valor predeterminado especificado?
Esencialmente, estoy tratando de convertir esto ...
private string _SomeVariable
public string SomeVariable
{
get
{
if(_SomeVariable == null)
{
_SomeVariable = SomeClass.IOnlyWantToCallYouOnce();
}
return _SomeVariable;
}
}
en algo diferente, donde puedo especificar el valor predeterminado y maneja el resto automáticamente ...
[SetUsing(SomeClass.IOnlyWantToCallYouOnce())]
public string SomeVariable {get; private set;}
c#
automatic-properties
ctorx
fuente
fuente
Respuestas:
No no hay. Las propiedades implementadas automáticamente solo funcionan para implementar las propiedades más básicas: campo de respaldo con getter y setter. No admite este tipo de personalización.
Sin embargo, puede usar el
Lazy<T>
tipo 4.0 para crear este patrónEste código calculará perezosamente el valor de
_someVariable
la primera vezValue
que se llame a la expresión. Solo se calculará una vez y almacenará en caché el valor para usos futuros de laValue
propiedad.fuente
SomeClass.IOnlyWantToCallYouOnce
en cuenta que en su ejemplo debe ser estático para ser utilizado con un inicializador de campo.Probablemente, lo más conciso que puede obtener es usar el operador de fusión nula:
fuente
IOnlyWantToCallYouOnce
devolucionesnull
lo llamará más de una vez._SomeVariable ?? ( _SomeVariable = SomeClass.IOnlyWantToCallYouOnce() );
- observe la adición del paréntesis alrededor de la configuración_SomeVariable
si es nulo.Lazy<>
, pero para nuestros propósitos esto funcionó mejor. Con la última versión de C #, también se puede escribir aún más conciso.=> _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());
Lo que algunos quizás no noten desde el primer vistazo es que el operador evalúa el operando de la derecha y devuelve su resultado .Hay una nueva característica en C # 6 llamada Expression Bodied Auto-Properties , que le permite escribirla un poco más limpia:
Ahora se puede escribir como:
fuente
IOnlyWantToCallYouOnce
se llamaría durante la construcción cada vez que se crea una instancia de la clase.SomeVariable
tiene carga perezosa.No así, los parámetros de los atributos deben tener un valor constante, no se puede llamar al código (incluso al código estático).
Sin embargo, es posible que pueda implementar algo con Aspectos de PostSharp.
Échales un vistazo:
PostSharp
fuente
Aquí está mi implementación de una solución a su problema. Básicamente, la idea es una propiedad que será establecida por una función en el primer acceso y los accesos posteriores producirán el mismo valor de retorno que el primero.
Luego para usar:
Por supuesto, existe la sobrecarga de pasar el puntero de función, pero hace el trabajo por mí y no noto demasiada sobrecarga en comparación con ejecutar el método una y otra vez.
fuente
Soy un gran admirador de esta idea y me gustaría ofrecer el siguiente fragmento de C # que llamé proplazy.snippet (puede importarlo o pegarlo en la carpeta estándar que puede obtener en el Administrador de fragmentos)
Aquí hay una muestra de su salida:
Aquí está el contenido del archivo de fragmentos: (guardar como proplazy.snippet)
fuente
No creo que esto sea posible con C # puro. Pero podría hacerlo usando un reescritor de IL como PostSharp . Por ejemplo, le permite agregar controladores antes y después de funciones según los atributos.
fuente
Lo hice así:
y luego puedes usarlo como
fuente
public ISet<String> RegularProperty {get;set} public string CalculatedProperty => this.LazyValue(() => { return string.Join(",", RegularProperty.ToArray()); });
Operator ?? = está disponible con C # 8.0 y versiones posteriores, por lo que ahora puede hacerlo aún más conciso:
fuente
https://github.com/bcuff/AutoLazy usa Fody para darte algo como esto
fuente
y llamo como bramido
fuente
Si usa un constructor durante la inicialización diferida, las siguientes extensiones también pueden ser útiles
Uso
fuente
LazyInitializer.EnsureInitialized()
? Porque por lo que puedo decir, además de la funcionalidad anterior,LazyInitializer
proporciona manejo de errores y funcionalidad de sincronización. Código fuente de LazyInitializer .