c# - query - EntitySet: ¿hay alguna razón para que IList.Add no se establezca?
linq entity framework c# (3)
Hay 3 formas de agregar elementos a la mayoría de las listas ...
- a través de un método de API público directo, típicamente
Add(SomeType)
- a través de la interfaz genérica
IList<T>.Add(T)
- a través del método de interfaz no genérico
IList.Add(object)
y normalmente espera que se comporten más o menos igual. Sin embargo, EntitySet<T>
LINQ es ... peculiar tanto en 3.5 como en 4.0; la API IList
no IList
el conjunto como "asignado" - los otros dos mecanismos sí lo hacen - esto suena trivial, pero es importante porque influye fuertemente en la serialización (es decir, hace que se omita) en el código repetitivo.
Ejemplo:
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
Ahora ... esto es profundamente sorprendente para mí; tanto que me tomó más de 2 horas de seguimiento hacia arriba a través del código para aislar lo que estaba sucediendo. Asi que...
¿Hay alguna razón sensata para esto? ¿O es solo un error?
(FWIW, también hubo un problema en el set.Assign(set)
en 3.5, pero ahora está arreglado en 4.0).
Curiosamente, esto ha sido identificado para varias versiones ahora (usted indicó que un problema de 3.5 se corrigió en 4.0). Aquí hay una publicación de 2007. El resto de los métodos IList
en 4.0 están correctamente relacionados con los métodos IList<T>
. Creo que hay 2 explicaciones probables (de la variedad bug / feature):
- Este es un error real que Microsoft aún no ha corregido.
- Esta es una característica que otros códigos de Microsoft están
aprovechandoaprovechando para agregar elementos sin establecer losHasLoadedOrAssignedValues
.
Probablemente ambas cosas: un error que cuenta con otro código dentro del marco. Parece que alguien se dijo a sí mismo:
Nadie realmente va a convertir esto en un IList y luego llama al método Add, ¿verdad?
Parece un error para mí. ILSpy muestra las diferencias entre las dos implementaciones:
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();
}
}
Parece que la implementación IList simplemente deja de llamar a un par de invocadores de eventos ( OnListChanged
y OnModified
) en los que LINQ to SQL probablemente confía para rastrear sus cambios. Si esto hubiera sido intencional, habría esperado que también dejaran de llamar a OnAdd
.
Por qué simplemente no tienen IList.Add
arrojan el valor a TEntity
y llaman al método genérico Add
, me supera.
Sorprendentemente, la diferencia parece radicada en el hecho de que los IList.Add
e IList<T>.Add
realidad tienen una semántica diferente :
- El método
IList.Add
falla si la entidad que se está agregando ya está presente - El
LIst<T>.Add
quita y luego vuelve a agregar una entidad si ya está presente
La razón aparente de esta diferencia es que el método de interfaz IList.Add
se define para devolver el índice de la entidad añadida, que para una implementación típica de IList.Add
siempre será el Count
de la recopilación anterior al Add
.
En cualquier caso, debido a que las dos implementaciones son intencionalmente diferentes, parece que los autores simplemente omitieron accidentalmente la llamada this.OnModified()
en la versión de IList.Add
.