mac*_*nir 10 c# generics delegates
我已经定义了一个泛型类" Lazy<T>",用于惰性评估和缓存委托的结果Func<T>.
我还定义了两个隐式转换运算符,所以我可以Lazy<T>从一个Func<T>s 创建一个,我可以分配Lazy<T>给一个T(得到Value的Lazy<T>)
我们的想法是,您可以传递Lazy<T>一个实例T,但不能在计算/检索值之前完成工作,直到将其分配给实际的实例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};
}
}
Run Code Online (Sandbox Code Playgroud)
但是这个类不能像我预期的那样工作,在下面的测试应用程序中突出显示:
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) };
}
}
Run Code Online (Sandbox Code Playgroud)
在标有的行上//ERROR,我收到编译错误:
错误CS0266:无法隐式转换Lazy<System.Collections.Generic.IList<string>>为System.Collections.Generic.IList<string>.存在显式转换(您是否错过了演员?)
此错误令人困惑,因为存在从源到目标类型的隐式转换.并且,从表面上看,代码块(3)与(1)做同样的事情.另外,它与(2)的区别仅在于用于专门化Lazy的类型.
任何人都可以向我解释这里发生了什么?
Jon*_*eet 17
问题是你试图IList<T>隐式地转换,并且IList<T>不包括IList<T>(即使它们是相同的类型) - 只考虑转换为非接口类型的包含.从C#3.0规范的6.4.3节:
如果从类型A到类型B存在标准隐式转换(第6.3.1节),并且如果A和B都不是接口类型,那么A被认为包含在B中,并且B被认为包含A.
在6.4.4节讨论用户定义的转换时,其中一个步骤是(强调我的):
- 找到适用的用户定义和提升转换运算符集合U.
该集合由D中的类或结构声明的用户定义和提升的隐式转换运算符组成,这些运算符从包含S 的类型转换为包含在T中的类型.如果U为空,则转换未定义,并发生编译时错误.
IList<T>不包括在内IList<T>,因此这一步骤失败了.
编译器会在其他场景中进行"链式"隐式转换 - 所以如果你真的有一个Lazy<List<T>>你可以写的:
object strings = lazyStrings;
Run Code Online (Sandbox Code Playgroud)
作品,因为List<T>被包围object(因为二者都是类,并有一个标准的隐式转换从List<T>到object).
至于为什么会出现这种情况,我怀疑它是为了阻止你期望引用转换的奇怪情况,但你实际上会得到隐式转换.假设我们有:
class ListLazy : Lazy<IList<string>>, IList<string>
{
// Stuff
}
...
Lazy<IList<string>> x = new ListLazy();
IList<string> list = x;
Run Code Online (Sandbox Code Playgroud)
应该使用哪种转换?从实际类型到... 的隐式引用转换,但编译器不知道,因为表达式是类型.基本上界面很尴尬,因为它们可以在类型层次结构中稍后显示,而对于一个类,你总是知道你在哪里,如果你看到我的意思.(禁止在同一层次结构中涉及两个类的隐式转换.)IList<string>Lazy<IList<string>>
| 归档时间: |
|
| 查看次数: |
2282 次 |
| 最近记录: |