好的,这有点奇怪.忽略我想要做的事情,并查看在这种情况下发生的结果.
代码:
static string rawNumbers="1,4,6,20,21,22,30,34";
static IEnumerable<int> numbers = null;
static void Main(string[] args)
{
numbers = rawNumbers.Split(',').Cast<int>();
for (int i = 0; i < numbers.Count(); i++)
{
//do something
}
}
Run Code Online (Sandbox Code Playgroud)
情况:
该行numbers = rawNumbers.Split(',').Cast<int>();
似乎有效,并且不会抛出任何异常.但是,当我遍历集合时,抛出InvalidCastException.
现在,深入了解源代码并查看CastIterator<TResult>
.这似乎是for (int i = 0; i < numbers.Count(); i++)
专门用来调用的numbers.Count()
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
foreach (object obj in source) yield return (TResult)obj;
}
Run Code Online (Sandbox Code Playgroud)
错误发生在演员表上,当我查看source
变量中的数据时,它是一个字符串[].
我会想到,因为我调用强制转换为成功执行int的行所以一切都很好.幕后发生了什么?字符串数组真的只是存储在某个地方,并且在被调用之前没有被转换为T吗?懒惰的铸造也许?
我知道我不能这样做:(int)"42".我的问题不是如何使演员工作,而是发生了什么.演员的延期执行?看起来很奇怪,我呼唤的线Cast<int>()
似乎工作,但实际上并没有.
Cod*_*lla 24
几件事情:第一,你不能投一个string
到int
.您可以解析字符串并获得结果整数.但基本上你是在尝试这样做:
int x = (int)"32";
Run Code Online (Sandbox Code Playgroud)
那是一个例外. 其次,LINQ运算符是延迟执行的,所以在你尝试迭代结果之前没有任何实际发生,那就是真正的工作开始发生的时候.
使用延迟执行时,不会检查您请求的操作是有效还是可以正确执行,它只是设置操作,然后尝试在迭代时单独执行.
如前所述,"延期执行"是此处的问题.在迭代结果变量之前,许多LINQ运算符不会导致lambda代码实际执行.
其中一个原因是允许您构建一系列可以一次执行的复杂操作,而不是作为一系列单独的操作.这可能是一件有用的事情 - 但如果你不期待它也会很棘手.
Cast
看起来有效的原因是因为IEnumerable
调用方法时不会枚举,而是在调用时枚举Count()
.所以,呼吁Cast()
真的什么都不做.一旦实际评估了Cast,代码就会失败.
而不是试图施放,只需做一个简单的转换.
numbers = rawNumbers.Split(',').Select(str => int.parse(str));
Run Code Online (Sandbox Code Playgroud)
您没有立即在该Cast<int>()
行发生错误的原因是因为记住这只是链接操作序列.只有在遍历集合后才会执行转换.
rawNumbers.Split(',')
马上发生,但Cast<int>()
延迟计算.
如果在该行上添加了ToList()或ToArray(),它将立即执行.
归档时间: |
|
查看次数: |
386 次 |
最近记录: |