I grabbed System.Linq.Dynamic.DynamicQueryable from here: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query开发者_JAVA技巧-library.aspx
The issue that I am running into is in code that looks like this:
var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);
It appears that if that line of code is executed by multiple threads near simultaneously, Microsoft's dynamic Linq code crashes in their ClassFactory.GetDynamicClass() method, which looks like this:
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();
}
}
The crash is a simple dictionary error: "An item with the same key has already been added."
In Ms code, The rwLock variable is a ReadWriterLock class, but it does nothing to block multiple threads from getting inside classes.TryGetValue() if statement, so clearly, the Add will fail.
I can replicate this error pretty easily in any code that creates a two or more threads that try to execute the Select("new") statement.
Anyways, I'm wondering if anyone else has run into this issue, and if there are fixes or workarounds I can implement.
Thanks.
I did the following (requires .NET 4 or later to use System.Collections.Concurrent
):
- changed the
classes
field to aConcurrentDictionary<Signature, Type>
, - removed all the
ReaderWriterLock rwLock
field and all the code referring to it, updated
GetDynamicClass
to:public Type GetDynamicClass(IEnumerable<DynamicProperty> properties) { var signature = new Signature(properties); return classes.GetOrAdd(signature, sig => CreateDynamicClass(sig.properties)); }
removed the
classCount
field and updatedCreateDynamicClass
to useclasses.Count
instead:Type CreateDynamicClass(DynamicProperty[] properties) { string typeName = "DynamicClass" + Guid.NewGuid().ToString("N"); ...
精彩评论