我刚刚调试完一个问题,我们的程序在生产服务器上崩溃,但从未在开发机器上崩溃。
我制作了这个小程序,我可以用它重现问题:
using System;
using System.Collections.Generic;
using System.Linq;
namespace RunTimeBug
{
class Program
{
static void Main(string[] args)
{
var coll = new Collection {{"Test", new Data()}, {"Test2", new Data()}};
var dataSequence = coll.Cast<Data>().ToList();
Console.WriteLine(dataSequence.Count);
}
}
class Collection : Dictionary<string,Data>, IEnumerable<Data>
{
public new IEnumerator<Data> GetEnumerator()
{
foreach(var v in Values)
yield return v;
}
}
class Data { }
}
在我的机器上运行时,此代码打印“2”。在生产服务器上运行时,它失败并出现以下异常:
Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.KeyValuePair
`2[System.String,RunTimeBug.Data]' to type 'RunTimeBug.Data'.
at System.Linq.Enumerable.<CastIterator>d__b0`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at RunTimeBug.Program.Main(String[] args)
我能在这些机器上找到的唯一区别是,CLR 运行时在机器上是 2.0.50727.4927 版,它可以工作,而在它不工作的机器上是 2.0.50727.1433 版。
据我所知,Cast 扩展方法在旧机器上获取错误版本的 IEnumerable,但在新机器上获取“正确”版本。
谁能解释为什么我会看到这个? 2 个 CLR 运行时版本之间发生了什么变化,这可能是造成这种情况的原因?
请注意,我已经部署了一个修复程序,并且我知道上面代码中的 Collection 类设计不佳,因为它实现了 2 个不同的 IEnumerable。这是在我们的产品中“在野外”发现的,所以我真的很想知道确切的原因。
最佳答案
我认为 Jason 链接到的文章中提到的修复与您在更高版本上运行的代码有关。我无权访问 Enumerable.Cast 的 SP1 之前版本,因此有点难以猜测。
有一件事是肯定的:一旦代码进入 Enumerable.CastIterator() ,那么它肯定不会在您的情况下工作。这会设置一个迭代器以将 IEnumerable 转换为 IEnumerable<>,并且该迭代器调用 GetEnumerator() 来初始化迭代器 block 。那只能调用 Dictionary.GetEnumerator(),而不是你的。将此 IEnumerable 返回的 KeyValuePair 转换为 Data 当然会失败,正如异常告诉您的那样。
当前版本的 Enumerable.Cast() 首先尝试将 IEnumerable 转换为 IEnumerable<>。那行得通。未使用 CastIterator()。
关于c# - 相同的代码在不同的机器上表现不同 - 可能是什么原因? (CLR 版本问题?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1827007/