gpt4 book ai didi

C# System.Collections.Generic.Dictionary`2.Insert - 已添加具有相同键的项目

转载 作者:行者123 更新时间:2023-11-30 15:20:31 27 4
gpt4 key购买 nike

这个问题是关于 .Net Framework 4.5 MVC Web 应用程序的。

我有一段我们继承并使用了多年的代码块,它一般将 DataTable 转换为 List ,其中一个私有(private)方法获取泛型类的属性列表,例如:

原始代码

    private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();

public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);

//get types
if (!typeDictionary.ContainsKey(typeof(T)))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}

//return
return typeDictionary[type];
}


没有什么令人兴奋的事情发生,只是确保 typeDictionary 不包含键(类型)并将其添加到字典中(key=type,value=properties),以便我们稍后可以访问它们。

我们通常将此代码用于任何类型的“模型”对象,但对于这个特定示例,这是在 2 个不同场合给我带来麻烦的代码。

模型对象

public class GetApprovalsByUserId
{
// constructor
public GetApprovalsByUserId()
{
TicketId = 0;
ModuleName = string.Empty;
ModuleIcon = string.Empty;
ApprovalType = string.Empty;
VIN = string.Empty;
StockNumber = string.Empty;
Year = 0;
Make = string.Empty;
Model = string.Empty;
Services = string.Empty;
RequestedDate = DateTime.MinValue;
}

// public properties
public int TicketId { get; set; }
public string ModuleName { get; set; }
public string ModuleIcon { get; set; }
public string ApprovalType { get; set; }
public string VIN { get; set; }
public string StockNumber { get; set; }
public int Year { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public string Services { get; set; }
public DateTime RequestedDate { get; set; }
}


同样,在那个特定的模型类中没有任何真正重要的事情发生,并且与我们在任何其他类中使用的没有任何不同。

就像我说的,我们在几个项目中普遍使用这段代码,并且从来没有遇到过问题,但在过去一天的 2 个不同场合,我们让它抛出以下异常:

已添加具有相同 key 的项目。

at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Utilities.Extensions.GetPropertiesForType[T]()
at Utilities.Extensions.ToObject[T](DataRow row)
at Utilities.Extensions.ToList[T](DataTable table)


如果有帮助,您可以在此处查看扩展方法所在的完整 Extensions.cs 类(静态):

https://pavey.azurewebsites.net/resources/Extensions.txt

我的问题是:

  1. 鉴于代码已经在执行 !typeDictionary.ContainsKey(typeof(T)) 检查,它怎么可能通过该测试,但在typeDictionary.Add(type, type.GetProperties().ToList()); 调用?

  2. 为什么会这么零星?它似乎在 99% 的时间都有效,使用相同的代码、相同的类(GetApprovalsByUserId,如上所示),并且在任何其他项目或任何其他模型类中从未失败过。

我们无法能够在任何环境中使用完全相同的代码、模型、数据或完全相同的设置来重现此问题,因此不确定如何再保护此代码比现在更好。

我的一个想法是将代码更改为:

提议的代码更改

    private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();

public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
IList<PropertyInfo> properties = null;

//get types
try
{
if (!typeDictionary.ContainsKey(type))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
}
catch
{
}

// try get value
typeDictionary.TryGetValue(type, out properties);

// return
return properties;
}


但是由于我一开始就无法重现错误,所以我也不完全确定这是否是防弹的。我的想法是,它只是 ContainsKey 的一些奇怪之处,特别是使用 typeof(T) 作为“键”时,它允许它在奇怪的情况下通过测试,而实际上不应该通过测试,但是 Add 失败,因为它知道 key 已经存在。因此,如果我尝试/捕获它,如果 ContainsKey 错误地告诉我它不存在,而实际上它不存在,Add 仍然会失败,但我会捕获它并继续,然后我可以 TryParse 获取值出来了,一切都会好起来的。

感谢任何想法、想法,或者特别是如何使用上面显示的原始代码重现问题,并提出改进建议以保护它。

最佳答案

您遇到的问题是并发访问。在检查和插入字典之间,另一个线程进来并添加了类型,导致第二次插入失败。

要解决此问题,您有两种选择:使用锁(如其他答案中所述)或使用 ConcurrentCollection:

using System.Collections.Concurrent;
private static ConcurrentDictionary<Type, IList<PropertyInfo>> typeDictionary = new ConcurrentDictionary<Type, IList<PropertyInfo>>();

public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);

typeDictionary.TryAdd(type, type.GetProperties().ToList());

//return
return typeDictionary[type];
}

如果值不存在则添加该值并返回true,否则什么都不做并返回false

关于C# System.Collections.Generic.Dictionary`2.Insert - 已添加具有相同键的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40004119/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com