C# 如何修复Windows API代码包中的ArgumentException?

C# 如何修复Windows API代码包中的ArgumentException?,c#,shell,plinq,windows-api-code-pack,C#,Shell,Plinq,Windows Api Code Pack,我已经创建了一个应用程序,它使用Windows API代码包从文件中读取属性。我在检索属性时遇到问题 var width = fileInfo.Properties.GetProperty(SystemProperties.System.Video.FrameWidth).ValueAsObject; 代码在这里中断给我 System.ArgumentException: An item with the same key has already been added. at Syste

我已经创建了一个应用程序,它使用Windows API代码包从文件中读取属性。我在检索属性时遇到问题

var width = fileInfo.Properties.GetProperty(SystemProperties.System.Video.FrameWidth).ValueAsObject;
代码在这里中断给我

System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Microsoft.WindowsAPICodePack.Shell.PropertySystem.ShellPropertyFactory.GenericCreateShellProperty[T](PropertyKey propKey, T thirdArg)
   at Microsoft.WindowsAPICodePack.Shell.PropertySystem.ShellProperties.GetProperty(PropertyKey key)
这主要发生在调用PLINQ中代码的这一部分时

.AsParallel().WithDegreeOfParallelism(_maxConcurrentThreads).ForAll(...)
即使度设置为1。如何解决这个问题?

根据建议,我可以通过修改包的源代码并在第57行和第62行添加锁来解决这个问题,如下所示

lock (_storeCache)
{
    if (!_storeCache.TryGetValue(hash, out ctor))
    {
        Type[] argTypes = { typeof(PropertyKey), typeof(ShellPropertyDescription), thirdType };
        ctor = ExpressConstructor(type, argTypes);
        lock (_storeCache)
            _storeCache.Add(hash, ctor);
    }
}

为了扩展您现有的答案,将字典切换到ConcurrentDictionary也可以解决这个问题,并且不再需要锁

    private static ConcurrentDictionary<int, Func<PropertyKey, ShellPropertyDescription, object, IShellProperty>> _storeCache
        = new ConcurrentDictionary<int, Func<PropertyKey, ShellPropertyDescription, object, IShellProperty>>();
...

    private static IShellProperty GenericCreateShellProperty<T>(PropertyKey propKey, T thirdArg)
    {
       ...

        Func<PropertyKey, ShellPropertyDescription, object, IShellProperty> ctor;
        ctor = _storeCache.GetOrAdd((hash, (key, args) -> {
            Type[] argTypes = { typeof(PropertyKey), typeof(ShellPropertyDescription), args.thirdType };
            return ExpressConstructor(args.type, argTypes);
        }, {thirdType, type});

        return ctor(propKey, propDesc, thirdArg);
    }
私有静态ConcurrentDictionary\u storeCache
=新的ConcurrentDictionary();
...
私有静态IShellProperty GenericCreateShellProperty(PropertyKey propKey,T thirdArg)
{
...
函数;
ctor=\u storeCache.GetOrAdd((散列,(键,参数)->{
Type[]argTypes={typeof(PropertyKey),typeof(ShellPropertyDescription),args.thirdType};
返回ExpressConstructor(args.type,argTypes);
},{thirdType,type});
返回选择器(propKey、propDesc、thirdArg);
}

听起来这个库不是线程安全的。如果你根本不使用PLinq,你会看到它吗?我做了很多尝试,但在不使用PLinq时从未看到过它。如果它不是线程安全的,我该怎么做才能保证它的安全?我可以在代码周围使用锁吗?或者我需要修改源代码吗?我建议从repo和reference下载代码g如果不使用包并对其进行调试,那么您将能够看到实际的问题是什么。内部锁是不必要的,您已经处于外部锁的独占部分,内部锁不起任何作用。更好的方法可能是去掉锁并用