我从这里抓取了System.Linq.Dynamic.DynamicQueryable:http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
我遇到的问题是在代码中看起来像这样:
var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);
如果这行代码几乎同时被多个线程执行,微软的动态Linq代码会在ClassFactory.GetDynamicClass()方法中崩溃,看起来像这样:
public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
{
rwLock.AcquireReaderLock(Timeout.Infinite);
try
{
Signature signature = new Signature(properties);
Type type;
if (!classes.TryGetValue(signature, out type))
{
type = CreateDynamicClass(signature.properties);
classes.Add(signature, type); // <-- crashes over here!
}
return type;
}
finally
{
rwLock.ReleaseReaderLock();
}
}
崩溃是一个简单的字典错误:"已经添加了具有相同键的项。"
在Ms代码中,rwLock变量是一个ReadWriterLock类,但它没有阻止多个线程进入类内部。trygetvalue () if语句,所以很明显,Add将失败。
我可以很容易地在任何代码中复制这个错误,创建两个或多个线程,试图执行Select("new")语句。
无论如何,我想知道是否有人遇到这个问题,如果有修复或变通方法,我可以实现。
谢谢。
我做了以下操作(要求。net 4或更高版本使用System.Collections.Concurrent
):
- 将
classes
字段更改为ConcurrentDictionary<Signature, Type>
, - 删除了所有的
ReaderWriterLock rwLock
字段和所有引用它的代码, -
更新
GetDynamicClass
为:public Type GetDynamicClass(IEnumerable<DynamicProperty> properties) { var signature = new Signature(properties); return classes.GetOrAdd(signature, sig => CreateDynamicClass(sig.properties)); }
-
删除
classCount
字段并更新CreateDynamicClass
以使用classes.Count
代替:Type CreateDynamicClass(DynamicProperty[] properties) { string typeName = "DynamicClass" + Guid.NewGuid().ToString("N"); ...