系统.林克.动态 .选择( "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);
如果这行代码几乎同时被多个线程执行,微软的动态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");
    ...
    

最新更新