私有成员变量在类后面的 ASP.NET 代码中真的是线程安全的吗?
我看到一个随机异常“集合已修改;枚举可能无法执行”- InvalidOperationException。
该异常指向下面代码片段中的 foreach 行,我知道在枚举时修改集合时会发生这种情况。
但是在我的场景中,我看不到发生这种情况的真正机会 - 除非私有成员不是线程安全的。我可能是错的,但这就是我需要帮助来理解和弄清楚的地方。
这是我的代码的样子
我的类后面有代码,它有一个私有集合,例如
private Dictionary<string, string> _someDictionary = SomeConstantClass.ConstantValue;
在页面预渲染完成事件中,我枚举字典
protected override void OnPagePreRenderComplete(object sender, EventArgs e){
_someDictionary["AnotherKey"] = "Another value";
foreach(var dataValuePair in _SomeDictionary){
//Do some operation
}
}
我还有一个可以修改此集合的公共属性,但它在 ascx 文件中设置,例如
<tc: UserControlA runat="server" id="abc" CustomProperty="true" />
和这是它的实现,
public bool CustomProperty{
set{
if (value)
_someDictionary["CustomProperty"] = "Custom Value";
}
}
它确实修改了我的成员变量集合 - 但根据我的理解,这个属性应该在 Control Init 本身中触发并完成。
因此,我仍然没有看到在预渲染完成事件期间修改集合的情况。
知道什么可能导致异常发生吗?
其他说明:该页面当然有许多更新面板,尽管此特定的用户控件没有做任何花哨的事情,甚至没有回发场景。 从日志中我看到问题发生在对页面的 HTTP GET 请求中。
此外:建议我一种重现此问题的方法(如果有的话)。
对于有兴趣了解 SomeConstantClass.ConstantValue 的朋友,这里是
class SomeConstantClass{
public static Dictionary<string, string> ConstantValue = new Dictionary<string, string> {
{"ABCD", "EFGH"},
{"HIJK", "LMNO"}
};
}
I am seeing a random exception "Collection was modified; enumeration may not execute" - InvalidOperationException.
The exception points to foreach line in the code snippet below, I know this happens when a collection is modified while enumerating.
However in my scenario, I don't see a real chance of it happening - UNLESS private member is not thread safe.. I may be wrong, but this where I need help to understand and figure out.
Here is how my code looks
I have code behind class which has a private collection like
private Dictionary<string, string> _someDictionary = SomeConstantClass.ConstantValue;
In the page prerender complete event, I am enumerating the dictionary
protected override void OnPagePreRenderComplete(object sender, EventArgs e){
_someDictionary["AnotherKey"] = "Another value";
foreach(var dataValuePair in _SomeDictionary){
//Do some operation
}
}
I also have a public property which can modify this collection, but it set in the ascx file like
<tc: UserControlA runat="server" id="abc" CustomProperty="true" />
and here is its implementation,
public bool CustomProperty{
set{
if (value)
_someDictionary["CustomProperty"] = "Custom Value";
}
}
It certainly modified my member variable collection - But as per my understanding this property should be fired and done in the Control Init itself.
So, I still dont see a scenario where the collection is modified during the pre render complete event.
Any idea what could cause the exception to occur??
other notes: the page certainly has many update panels though this specific usercontrol does not do anything fancy and does not even have postback scenario.
From the log I see that the issue is happening in HTTP GET request to the page.
Moreover: Suggest me a way (if any) to reproduce this.
For my friends who were interested to know the SomeConstantClass.ConstantValue, here it is
class SomeConstantClass{
public static Dictionary<string, string> ConstantValue = new Dictionary<string, string> {
{"ABCD", "EFGH"},
{"HIJK", "LMNO"}
};
}
如果您从
SomeConstantClass.ConstantValue
返回相同的实例,则多个页面将具有指向同一对象的私有成员变量。这将导致对象在一个页面的初始化时发生更改,同时在另一页面的 OnPagePreRenderComplete 上进行迭代。确保在每次访问
SomeConstantClass.ConstantValue
时返回字典的新实例。示例:这样每个页面都有自己的字典对象可以使用。这是快速的解决方案,您可以重构逻辑,这样您就不需要为每个页面创建新的字典。
基本上,私有成员变量只有在引用该页面私有的对象并且没有其他人知道该对象或者该对象本身被设计为线程安全的情况下才是线程安全的。通过私有成员封装对非线程安全静态对象的访问不会使其成为线程安全的。
If you are returning the same instance from
SomeConstantClass.ConstantValue
then multiple pages will have the private member variable pointing to the same object. This will lead to the object being changed on the init of one page while its being iterated on theOnPagePreRenderComplete
of another page.Make sure that you return a new instance of the dictionary in each access to
SomeConstantClass.ConstantValue
. Example:This way each page will have it own dictionary object to work with. This is the quick solution, you could refactor the logic so that you don't need to have to create a new dictionary for each page.
Basically private member variables are only thread safe if they reference an object that is private to that page and no one else knows about that object or the object itself is designed to be thread-safe. Encapsulating access to a non thread-safe static object through a private member will not make it thread safe.