EntitySet - IList.Add 没有设置分配是否有合理的原因?
有 3 种方法可以将项目添加到大多数列表...
- 通过直接公共 API 方法,通常
- 通过通用
IList
Add(SomeType) >.Add(T) - 通过非泛型
IList.Add(object)
接口方法
进行接口,您通常期望它们的行为或多或少相同。然而,LINQ 的 EntitySet
在 3.5 和 4.0 上都是特有的; IList
API 不会将集合标记为“已分配” - 其他两种机制会< /strong> - 这听起来微不足道,但很重要,因为它严重影响样板代码中的序列化(即导致其被跳过)。
示例:
EntitySet<string> set1 = new EntitySet<string>();
set1.Add("abc");
Debug.Assert(set1.Count == 1); // pass
Debug.Assert(set1.HasLoadedOrAssignedValues, "direct"); // pass
EntitySet<string> set2 = new EntitySet<string>();
IList<string> typedList = set2;
typedList.Add("abc");
Debug.Assert(set2.Count == 1); // pass
Debug.Assert(set2.HasLoadedOrAssignedValues, "typed list"); // pass
EntitySet<string> set3 = new EntitySet<string>();
IList untypedList = set3;
untypedList.Add("abc");
Debug.Assert(set3.Count == 1); // pass
Debug.Assert(set3.HasLoadedOrAssignedValues, "untyped list"); // FAIL
现在……这让我深感惊讶;如此之多以至于我花了两个多小时通过代码向上跟踪来隔离发生的事情。那么...
这有任何合理的理由吗?或者这只是一个错误?
(FWIW,3.5 中的 set.Assign(set)
也存在问题,但现在已在 4.0 中修复。)
There are 3 ways of adding items to most lists...
- via a direct public API method, typically
Add(SomeType)
- via the generic
IList<T>.Add(T)
interface - via the non-generic
IList.Add(object)
interface method
and you normally expect them to behave more or less the same. However, LINQ's EntitySet<T>
is... peculiar on both 3.5 and 4.0; the IList
API does not flag the set as "assigned" - the other two mechanisms do - this sounds trivial, but it is important in that it heavily influences serialization (i.e. causes it to be skipped) in the boilerplate code.
Example:
EntitySet<string> set1 = new EntitySet<string>();
set1.Add("abc");
Debug.Assert(set1.Count == 1); // pass
Debug.Assert(set1.HasLoadedOrAssignedValues, "direct"); // pass
EntitySet<string> set2 = new EntitySet<string>();
IList<string> typedList = set2;
typedList.Add("abc");
Debug.Assert(set2.Count == 1); // pass
Debug.Assert(set2.HasLoadedOrAssignedValues, "typed list"); // pass
EntitySet<string> set3 = new EntitySet<string>();
IList untypedList = set3;
untypedList.Add("abc");
Debug.Assert(set3.Count == 1); // pass
Debug.Assert(set3.HasLoadedOrAssignedValues, "untyped list"); // FAIL
Now... this is deeply surprising to me; so much so that it took me over 2 hours of tracking upwards through code to isolate what was happening. So...
is there any sane reason for this? Or is this just a bug?
(FWIW, there was also an issue in set.Assign(set)
in 3.5, but this is now fixed in 4.0.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有趣的是,现在多个版本都已经发现了这个问题(您说 3.5 的问题已在 4.0 中修复)。 这是 2007 年的帖子. 4.0 中的其余
IList
方法已正确绑定到IList
方法。我认为有两种可能的解释(关于错误/功能多样性):利用利用此功能来添加项目,而无需设置HasLoadedOrAssignedValues
。这可能是两者兼而有之 - 框架内其他代码所指望的错误。听起来就像有人对自己说:
Interestingly, this has been identified for several versions now (you stated that a 3.5 issue was fixed in 4.0). Here is a post from 2007. The rest of the
IList
methods in 4.0 are correctly tied to theIList<T>
methods. I think that there are 2 likely explanations (of the bug/feature variety):exploitingleveraging to add items without setting theHasLoadedOrAssignedValues
.It is probably both - a bug that other code inside the framework is counting on. Sounds like someone said to themselves:
令人惊讶的是,这种差异似乎根源于
IList.Add
和IList.Add
方法实际上具有不同的语义LIst.Add
方法会删除实体,然后重新添加已存在的实体明显原因为了这区别在于
IList.Add
接口方法被定义为返回添加实体的索引,对于IList.Add
的典型实现来说,该索引始终是Count
。添加
之前集合的无论如何,由于这两个实现是有意不同的,因此作者似乎只是无意中省略了
IList.Add
版本中的this.OnModified()
调用。Surprisingly, the difference seems rooted in the fact that the
IList.Add
andIList<T>.Add
methods actually have different semantics:IList.Add
method fails if the entity being added is already presentLIst<T>.Add
method removes and then re-adds an entity if is is already presentThe apparent reason for this difference is that
IList.Add
interface method is defined to return the index of the added entity, which for a typical implementation ofIList.Add
will always be theCount
of the collection prior to theAdd
.In any case, because the two implementations are intentionally different, it seems the authors simply accidentally omitted the
this.OnModified()
call in theIList.Add
version.对我来说看起来像一个错误。 ILSpy 显示了两种实现之间的差异:
看起来 IList 实现只是忽略了调用 LINQ to SQL 可能依赖的几个事件调用程序(
OnListChanged
和OnModified
)来跟踪其变化。如果这是故意的,我会期望他们也省略对OnAdd
的调用。为什么他们不简单地让
IList.Add
将值转换为TEntity
并调用通用的Add
方法,这超出了我的理解。Looks like a bug to me. ILSpy shows the differences between the two implementations:
It looks like the IList implementation simply neglects to call a couple of event invokers (
OnListChanged
andOnModified
) that LINQ to SQL probably relies on to track its changes. If this had been intentional, I would have expected them to also leave out the call toOnAdd
.Why they don't simply have
IList.Add
cast the value toTEntity
and call the genericAdd
method is beyond me.