He definido una clase genérica "Lazy<T>
", para la evaluación diferida y el almacenamiento en caché del resultado de un delegado Func<T>
.¿Por qué no funciona este uso de moldes implícitos?
que también definen dos operadores de conversión implícitas para que pueda crear un Lazy<T>
desde unos Func<T>
s, y puedo asignar un Lazy<T>
a un T
(obtiene el Value
del Lazy<T>
)
La idea es que se puede pasar alrededor de Lazy<T>
en lugar de una instancia de T
, pero no hacer el trabajo para calcular/recuperar el valor hasta que se asigne a una instancia real de T
.
// class Lazy<T>
// Encapsulates a value which can be retrieved when first accessed,
// and is then cached.
class Lazy<T>
{
private Func<T> _getter;
private T _cached;
private bool _isCached;
// Get/set the getter delegate
// that 'calculates' the value.
public Func<T> Getter
{
get
{
return _getter;
}
set
{
_getter = value;
_cached = default(T);
_isCached = false;
}
}
// Get/set the value.
public T Value
{
get
{
if (!_isCached)
{
_cached = Getter();
_isCached = true;
_getter = null;
}
return _cached;
}
set
{
_cached = value;
_isCached = true;
_getter = null;
}
}
// Implicit casts:
// Create a T from a Lazy<T>
public static implicit operator T(Lazy<T> lazy)
{
return lazy.Value;
}
// Create a Lazy<T> from a Func<T>
public static implicit operator Lazy<T>(Func<T> getter)
{
return new Lazy<T> {Getter = getter};
}
}
Pero esta clase no funciona como esperaba en un caso, se destaca en la aplicación de pruebas a continuación:
class Program
{
static void Main()
{
// This works okay (1)
TestLazy(() => MakeStringList());
// This also works (2)
Lazy<string> lazyString = new Func<string>(() => "xyz");
string s = lazyString;
//This doesn't compile (3)
//
Lazy<IList<string>> lazyStrings = new Func<IList<string>>(MakeStringList);
IList<string> strings = lazyStrings; //ERROR
}
static void TestLazy<T>(Func<T> getter)
{
Lazy<T> lazy = getter;
T nonLazy = lazy;
}
private static IList<string> MakeStringList()
{
return new List<string> { new string('-', 10) };
}
}
En la línea marcada con //ERROR
, me sale un error de compilación:
error CS0266: No se puede convertir implícitamente el tipo Lazy<System.Collections.Generic.IList<string>>
en System.Collections.Generic.IList<string>
. Existe una conversión explícita (¿falta un molde?)
Este error es confuso ya que existe una conversión implícita del origen al tipo de destino en cuestión. Y, a primera vista, el fragmento de código (3) está haciendo lo mismo que (1) Además, difiere de (2) solo por el tipo utilizado para especializar al Lazy.
¿Alguien puede explicarme qué está pasando aquí?
Lo extraño es que el error de compilación todavía ocurre cuando List se reemplaza por IList (aparte de donde se construye una instancia de List y se devuelve desde un método que devuelve IList. – mackenir
Para ser precisos, ahora el compilador se queja de que no hay implícito emitido desde "Lazy" hasta "T", donde "T == IList ". Aunque fui y edité la pregunta, puede ser que su respuesta aún se mantenga, en cuyo caso tendré que recurrir una investigación qué 'abarca' es para entender la respuesta :) –
mackenir
Pero el punto es que todavía estás tratando de convertir a * interfaz * - eso es lo que no le gusta. –