我有一段我们继承并使用多年的代码块,它通用地将 DataTable 转换为 List<T>,其中一个私有方法获取一个泛型类的属性列表,例如: 原始代码
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),以便我们稍后可以访问它们。
我们通常将此代码用于任何类型的“模型”对象,但对于这个特定的示例,这是我在两个不同场合遇到过麻烦的地方。
模型对象
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; }
}
再次强调,在这个特定的模型类中没有什么真正重要的事情发生,也没有任何与我们在其他类中使用的不同之处。
就像我说的,我们在几个项目中通用地使用这段代码,从来没有出现过问题,但是在过去的一天里,我们已经两次遇到了以下异常:
已经添加了具有相同键的项。
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
我的问题是:
考虑到代码已经进行了 !typeDictionary.ContainsKey(typeof(T)) 检查,它怎么可能通过这个测试,然后在 typeDictionary.Add(type, type.GetProperties().ToList()); 调用时失败?
为什么会如此不稳定?它似乎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)作为“键”,这使得它可以在奇怪的情况下通过测试,而它实际上不应该通过测试,但由于已知该键已经存在,所以添加操作失败了。因此,如果我尝试/捕获它,如果ContainsKey错误地告诉我它不存在,当实际上它存在时,添加操作仍将失败,但我会捕获它,并继续执行,然后我可以尝试解析以获取值,一切应该都很好。
感谢您提供任何想法、建议,或具体说明如何重现上面所示的原始代码的问题,以及推荐改进方法以保护它。
!typeDictionary.ContainsKey(typeof(T))
的检查,那么它怎么可能通过这个测试,但在typeDictionary.Add(type, type.GetProperties().ToList())
调用上失败呢? -- 竞态条件? - Robert HarveyAdd
),而是一个字典调整大小的问题。 - Matt Burland