多线程 – System.Linq.Dynamic .Select(“new …”)似乎不是线程安全的

我从这里抓住了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);

看来,如果这行代码由多个线程同时执行,那么Microsoft的动态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类,但是它不会阻止多个线程进入类内部.如果语句,则尝试GetGetValue(),显然,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");
...
点赞