我在一个ASP.Net 2.0项目,在C#.我有一些数据被存储在会话状态.为了易于使用,它被包裹在一个属性,像这样:
protected IList<Stuff> RelevantSessionData { get { return (IList<Stuff>) Session["relevant_key"]; } set { Session["relevant_key"] = value; } }
获取和设置值的工作原理与您预期的一致.如果我想清除这个值,我只是把它设置为null,没有任何问题.但是,在另一个开发人员的页面中,他调用了集合的Clear()方法.我以为这会是一个bug,但它似乎工作,我不明白为什么.它的工作原理如下:
Debug.WriteLine(RelevantSessionData.Count); //outputs,say,3 RelevantSessionData.Clear(); Debug.WriteLine(RelevantSessionData.Count); //outputs 0
为什么这样做?我的天真的期望将是中间线从会话加载序列化值,反序列化到一个对象中,调用该对象上的Clear(),然后让未命名的对象落在范围之外.这将是一个错误,因为存储在Session中的值将保持不变.但显然,它足够聪明,而是调用属性设置器并将新更改的集合序列化为会话.
这让我有点紧张,因为我们的遗留代码中有地方有属性设置者有副作用,如果不是这样,我不希望那些被调用.
在这样的情况下,属性设置器是否总是被调用?还有其他事情吗?还是我完全误解这里发生了什么?
[补充说明答案]
事实证明是误会了.我知道存储在Session中的对象必须是可序列化的,并且基于此,我对集合在内部的行为做了太多的假设.我反思了
存储对象(我的IList)只有一个实例.对getter的每次调用都会返回同一个实例的引用.所以上面引用的代码就像它出现一样,没有任何特殊的魔法.
并回答标题问题:不,设置者不被隐含地称为.
解决方法
是的,你是对的,如果你的setter / getter是序列化/反序列化对象,这将是一个bug.但事实并非如此.相反,你是基于参考传递.
所以基本上发生的是,你的例子中的第一行通过get获取项目,Count是基于这个调用的.然后,第二行正在出来,调用再次返回,返回相同的对象,运行清除,然后第三行正在执行与第一行相同的操作.
如果你写了这样的设置者/吸气器,你会有一个“错误”
protected IList<Stuff> RelevantSessionData { get { return (IList<Stuff>) JSON.ConvertFromString(Session["relevant_key"]); } set { Session["relevant_key"] = JSON.ConvertToString(value); } }
在这种情况下,将创建一个新对象,并为每个调用get块创建一个对象.但是,由于上面的例子只是传递对同一个对象的引用,所以你不会看到这个“bug”.
而且我说“bug”,因为它不是真的是一个bug,这只是一个误解了幕后发生的事情.
我希望这有帮助.