40 votes

EntitySet - y a-t-il une raison valable pour que IList.Add ne définisse pas l'affectation ?

Il existe 3 façons d'ajouter des éléments à la plupart des listes...

  • via une méthode publique directe de l'API, généralement Add(SomeType)
  • via le générique IList<T>.Add(T) interface
  • par le biais de la méthode non générique IList.Add(object) méthode d'interface

et vous attendez normalement d'eux qu'ils se comportent plus ou moins la même chose. Cependant, la méthode LINQ EntitySet<T> est... particulier à la fois en 3.5 et en 4.0 ; la fonction IList API n'est pas signaler l'ensemble comme étant "attribué" - les deux autres mécanismes faire - Cela semble trivial, mais c'est important dans la mesure où cela influence fortement la sérialisation (c'est-à-dire que cela la fait sauter) dans le code passe-partout.

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

Maintenant... c'est profondément surprenant pour moi ; à tel point qu'il m'a fallu plus de 2 heures de traque à travers le code pour isoler ce qui se passait. Alors...

est là tout une raison saine pour cela ? Ou s'agit-il simplement d'un bug ?

(FWIW, il y a aussi eu un problème en set.Assign(set) en 3.5, mais cela est maintenant corrigé en 4.0).

20voto

Ethan Cabiac Points 3669

Il est intéressant de noter que ce problème a été identifié depuis plusieurs versions maintenant (vous avez déclaré qu'un problème de la version 3.5 a été corrigé dans la version 4.0). Voici un billet datant de 2007. Le reste de la IList dans la version 4.0 sont correctement liées à la fonction IList<T> méthodes. Je pense qu'il y a deux explications probables (de type bug/caractéristique) :

  1. Il s'agit d'un bogue réel que Microsoft n'a pas encore corrigé.
  2. Il s'agit d'une fonctionnalité que d'autres codes Microsoft utilisent. en exploitant levier pour ajouter des éléments sans la mise en place de la HasLoadedOrAssignedValues .

C'est probablement les deux - un bug sur lequel d'autres codes du framework comptent. On dirait que quelqu'un s'est dit :

Personne ne va vraiment transformer cette liste en une IList, puis appeler la méthode Add, n'est-ce pas ?

8voto

Rick Sladkey Points 23389

De manière surprenante, la différence semble s'enraciner dans le fait que les IList.Add y IList<T>.Add Les méthodes ont en fait sémantique différente :

  • El IList.Add La méthode échoue si l'entité à ajouter est déjà présente.
  • El LIst<T>.Add supprime et ajoute à nouveau une entité si elle est déjà présente.

La raison apparente de cette différence est que IList.Add est définie pour renvoyer l'index de l'entité ajoutée, ce qui, pour une mise en œuvre typique de l'interface IList.Add sera toujours le Count de la collection avant la Add .

Quoi qu'il en soit, comme les deux implémentations sont intentionnellement différentes, il semble que les auteurs aient simplement omis par accident l'option this.OnModified() dans l'appel IList.Add version.

4voto

StriplingWarrior Points 56276

Ça ressemble à un bug pour moi. ILSpy montre les différences entre les deux implémentations :

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();
    }
}

Il semble que l'implémentation d'IList néglige simplement d'appeler quelques invokers d'événements ( OnListChanged y OnModified ) sur lequel LINQ to SQL s'appuie probablement pour suivre ses changements. Si cela avait été intentionnel, je me serais attendu à ce qu'ils laissent également de côté l'appel à OnAdd .

Pourquoi ils n'ont pas simplement IList.Add convertir la valeur en TEntity et appeler le générique Add Je ne comprends pas cette méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X