System.Linq.Dynamic.Select ("new ...") does not look thread safe

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-library .aspx

The problem I am facing is code that looks like this:

var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5); 

It appears that if this line of code is executed by multiple threads at the same time, Microsoft's dynamic Linq code causes an error in the 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(); } } 

Failure is a simple dictionary error: "An item with the same key has already been added."

In the Ms code, the rwLock variable is a ReadWriterLock class, but it does nothing to block multiple threads from getting inside classes. TryGetValue () If the statement, it is so clear that Add will fail.

I can easily reproduce this error in any code that creates two or more threads that try to execute the Select ("new") statement.

In any case, I am wondering if anyone else has run into this problem, and if there are fixes or workarounds that I can implement.

Thanks.

+4
source share
1 answer

I did the following (requires .NET 4 or newer to use System.Collections.Concurrent ):

  • changed the classes field to ConcurrentDictionary<Signature, Type> ,
  • deleted the entire ReaderWriterLock rwLock field and all the code that refers 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 updated CreateDynamicClass instead of classes.Count :

     Type CreateDynamicClass(DynamicProperty[] properties) { string typeName = "DynamicClass" + Guid.NewGuid().ToString("N"); ... 
+2
source

All Articles