Подтвердить что ты не робот

EntitySet - есть ли разумная причина, по которой IList.Add не назначается?

Есть 3 способа добавления элементов в большинство списков...

  • с помощью прямого публичного API-метода, обычно Add(SomeType)
  • через общий интерфейс IList<T>.Add(T)
  • через не общий метод интерфейса IList.Add(object)

и вы обычно ожидаете, что они будут вести себя более или менее одинаково. Однако LINQ EntitySet<T> является... особенным как для 3.5, так и для 4.0; API IList не указывает флаг как "назначенный" - другие два механизма do - это звучит тривиально, но важно, чтобы он сильно влиял на сериализацию ( т.е. приводит к его пропуску) в код шаблона.

Пример:

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, проблема была в set.Assign(set) в 3.5, но теперь это исправлено в 4.0.)

4b9b3361

Ответ 1

Интересно, что это было идентифицировано для нескольких версий сейчас (вы заявили, что проблема 3.5 была исправлена ​​в 4.0). Вот сообщение от 2007. Остальные методы IList в 4.0 правильно привязаны к методам IList<T>. Я думаю, что есть 2 вероятных объяснения (разнообразия ошибок/признаков):

  • Это настоящая ошибка, которую Microsoft еще не исправила.
  • Это функция, в которой используется другой код Microsoft , использующий для добавления элементов без установки HasLoadedOrAssignedValues.

Вероятно, и то, и другое - ошибка, на которую рассчитывает другой код внутри фреймворка. Похоже, кто-то сказал себе:

Никто не собирается вносить это в IList, а затем вызывает метод Add, правильно?

Ответ 2

Удивительно, но разница, по-видимому, связана с тем, что методы IList.Add и IList<T>.Add действительно имеют различную семантику:

  • Метод IList.Add завершается с ошибкой, если добавляемый объект уже присутствует
  • Метод LIst<T>.Add удаляет, а затем повторно добавляет объект, если он уже присутствует.

Очевидная причина этой разницы заключается в том, что метод интерфейса IList.Add определен для возврата индекса добавленного объекта, который для типичной реализации IList.Add всегда будет Count коллекции до Add.

В любом случае, поскольку две реализации преднамеренно различны, кажется, что авторы просто случайно опустили вызов this.OnModified() в версии IList.Add.

Ответ 3

Похож на ошибку. 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 просто пренебрегает вызовом нескольких вызывающих события (OnListChanged и OnModified), которые, вероятно, полагаются на LINQ to SQL для отслеживания изменений. Если бы это было намеренно, я бы ожидал, что они также оставят звонок OnAdd.

Почему у них нет просто IList.Add, чтобы передать значение TEntity и вызвать общий метод Add вне меня.