I've defined a generic class "Lazy<T>
", for lazy evaluation and caching of the result of a delegate Func<T>
.
I also define two implicit cast operators so I can create a Lazy<T>
from a Func<T>
s, and I can assign a Lazy<T>
to a T
(gets the Value
of the Lazy<T>
)
The idea is that you can pass around a Lazy<T>
in place of an instance of T
, but not do the work to calculate/retrieve the value until it is assigned to an actual instance of 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};
}
}
But this class doesn't work as I expected in one case, highlighted in the test app below:
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) };
}
}
On the line marked with //ERROR
, I get a compile error:
error CS0266: Cannot implicitly convert type Lazy<System.Collections.Generic.IList<string>>
to System.Collections.Generic.IList<string>
. An explicit conversion exists (are you missing a cast?)
This error is confusing as there does exist an implicit cast from the source to the target type in question. And, on the face of it, code chunk (3) is doing the same thing as (1) Also, it differs from (2) only by the type used to specialize the Lazy.
Can anyone explain to me what's going on here?