有三种方法可以将项目添加到大多数列表中......
Add(SomeType)
IList<T>.Add(T)
界面IList.Add(object)
接口方法并且您通常希望他们的行为或多或少相同。但是,LINQ的EntitySet<T>
在3.5和4.0上都是奇特的; IList
API 不 将该设置标记为“已分配” - 其他两种机制 执行 - 这听起来微不足道,但重要的是它会严重影响样板代码中的序列化(即导致它被跳过)。
示例:
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
现在......这让我感到非常惊讶;以至于我花了2个多小时跟踪代码以隔离发生的事情。所以......
是否有 任何 理智的理由?或者这只是一个错误?
(FWIW,3.5中的set.Assign(set)
也存在问题,但现在已在4.0中修复。)
答案 0 :(得分:20)
有趣的是,现在已经确定了几个版本(你说明在4.0中修复了3.5版本)。 Here is a post from 2007. 4.0中的其他IList
方法与IList<T>
方法正确绑定。我认为有两种可能的解释(错误/特征变种):
HasLoadedOrAssignedValues
。这可能是两者 - 框架内的其他代码所依赖的错误。听起来有人对自己说:
没有人真的要将它转换为IList,然后调用Add方法,对吗?
答案 1 :(得分:8)
令人惊讶的是,差异似乎源于IList.Add
和IList<T>.Add
方法实际上具有不同的语义:
IList.Add
方法将失败LIst<T>.Add
方法删除然后重新添加实体(如果已存在)这种差异的明显原因是IList.Add
接口方法被定义为返回已添加实体的索引,对于IList.Add
的典型实现,该索引始终为Count
Add
之前的集合。
在任何情况下,由于这两个实现有意不同,似乎作者只是意外地忽略了this.OnModified()
版本中的IList.Add
调用。
答案 2 :(得分:4)
对我来说看起来像个错误。 ILSpy显示了两种实现之间的差异:
int IList.Add(object value)
{
TEntity tEntity = value as TEntity;
if (tEntity == null || this.IndexOf(tEntity) >= 0)
{
throw Error.ArgumentOutOfRange("value");
}
this.CheckModify();
int count = this.entities.Count;
this.entities.Add(tEntity);
this.OnAdd(tEntity);
return count;
}
// System.Data.Linq.EntitySet<TEntity>
/// <summary>Adds an entity.</summary>
/// <param name="entity">The entity to add.</param>
public void Add(TEntity entity)
{
if (entity == null)
{
throw Error.ArgumentNull("entity");
}
if (entity != this.onAddEntity)
{
this.CheckModify();
if (!this.entities.Contains(entity))
{
this.OnAdd(entity);
if (this.HasSource)
{
this.removedEntities.Remove(entity);
}
this.entities.Add(entity);
this.OnListChanged(ListChangedType.ItemAdded, this.entities.IndexOf(entity));
}
this.OnModified();
}
}
看起来IList实现只是忽略了调用LINQ to SQL可能依赖于跟踪其更改的几个事件调用者(OnListChanged
和OnModified
)。如果这是故意的话,我原以为他们也会忽略对OnAdd
的号召。
为什么他们不仅仅IList.Add
将值转换为TEntity
并且调用通用Add
方法超出了我的范围。