Операция может дестабилизировать время выполнения?

У меня проблемы с пониманием проблемы. У меня есть немного кода, который извлекает записи из базы данных с помощью LINQ и помещает их в объект, который передается в интерфейс. Это выглядит примерно так:

public IEnumerable<ISomeObject> query()
{
    return from a in dc.SomeTable
           select new SomeObject
           {
             //Assign various members here
           } as ISomeObject;
}

Когда я проверяю это, я помещаю возвращаемый IEnumerable в переменную, называемую результатами, и запускаю эту строку:

Assert.AreEqual(EXPECTED_COUNT, results.Count());

Когда это выполняется, я получаю сообщение System.Security.VerificationException: "Операция может дестабилизировать время выполнения".

Я нашел решение здесь, вот что:

var results = from a in dc.SomeTable
              select new SomeObject
              {
                //Assign various members here
              } as ISomeTable;
return results.OfType<ISomeObject>();

Это работает, но мне трудно понять, что здесь происходит. Почему я получил исключение в первую очередь и как изменили строки кода выше? Документация MSDN, похоже, предполагает, что это проблема безопасности типов, но я не вижу, где предыдущий код был небезопасным.

UPDATE Немного больше информации я узнал. Первый пример работает, если я делаю возвращаемый тип IQueryable. Это проливает немного больше света на то, что происходит не так, но я все еще смущен о том, почему. Почему компилятор не заставил меня включить IEnumerable в IQueryable?

Ответ 1

Я считаю, что это проблема ковариации или контравариантности, отмеченная этот пост форума.

См. Ковариация и контравариантность в С#, часть вторая: Ковариация массивов и остальная часть Серия ковариации и контравариантности в блоге Эрика Липперта.

Хотя он имеет дело с массивами в статье, которую я связал, я считаю, что подобная проблема возникает здесь. В первом примере вы возвращаете IEnumerable, который может содержать объекты, которые реализуют интерфейс, который больше, чем ISomeTable (т.е. Вы можете поместить Черепаха в Животные IEnumerable, когда этот IEnumerable может содержать только Жирафов). Я думаю, что причина, по которой она работает, когда вы возвращаете IQueryable, состоит в том, что она больше/больше, чем все, что вы могли бы вернуть, поэтому вы гарантированы, что то, что вы вернете, сможет обрабатывать (?).

Во втором примере OfType гарантирует, что возвращаемое является объектом, который хранит всю информацию, необходимую для возврата только тех элементов, которые могут быть брошенным к Жирафу.

Я уверен, что это имеет какое-то отношение к проблемам безопасности типов, описанным выше, но, как говорит Эрик Липперт Функции более высокого порядка Hurt My Brain, и у меня возникают проблемы с выражением именно того, почему это является проблемой/контравариантом.

Ответ 2

Я нашел эту запись, ища собственное решение "операция может дестабилизировать время выполнения". Хотя приведенная выше рекомендация по ковариации/противоречивости выглядит очень интересной, в конце я обнаружил, что получаю то же сообщение об ошибке, запустив мои модульные тесты с включенным охватом кода и установленным атрибутом сборки AllowPartiallyTrustedCallers.

Удаление атрибута AllowPartiallyTrustedCallers заставило мои тесты работать нормально. Я также мог отключить покрытие кода, чтобы они запускались, но это не было приемлемым решением.

Надеюсь, это поможет кому-то другому, кто сделает это на этой странице, пытаясь найти решение этой проблемы.

Ответ 3

Просто предположим, но оператор как может вернуть нуль - так что это может быть связано с фактической реализацией кода new SomeObject { ... }, так как это синтаксический сахар. Фильтры return results.OfType<ISomeTable>();, основанные на типе, поэтому оператор return вашего метода вернет этот тип (обеспечивая безопасность типа). Я столкнулся с аналогичной проблемой с возвратом типичных типов.

P.S. Мне нравится "Операция может дестабилизировать время исполнения". исключение. Это почти похоже на исключение "Вы могли бы взорвать интернет".

Ответ 4

Я столкнулся с этой ошибкой с похожим кодом;

IEnumerable<Table> records = (from t in db.Tables
                              where t.Id.Equals(1)
                              select t).ToList();

Этот, казалось бы, безобидный код был частью метода UserControl, который был вызван с страницы. Однако никаких проблем в среде разработки .NET4, когда сайт был предварительно скомпилирован и развернут на сервере .NET3.5, я получил эту ошибку.

Я подозреваю, что это связано с тем, что элемент управления компилируется в отдельную DLL в сочетании с изменениями безопасности между фреймворками, как описано в this Блог безопасности .NET

Мое решение: запустите live-сайт на .NET4

Ответ 5

Не удалось ли это сделать, если вы измените это:

select new SomeObject { ... } as ISomeTable;

:

select (ISomeTable) new SomeObject { ... };

?

Если это так (как я вижу, вы подтвердили), возможно, это связано с тем, что реализация интерфейса может быть либо классом, либо структурой? Проблема возникает, если вы отбрасываете абстрактный класс, а не интерфейс?

Ответ 6

Я обнаружил, что у OfType были некоторые неприятные побочные эффекты при использовании linq для sql. Например, части linq, которые ранее были оценены после того, как запрос был запущен против db, были переведены на SQL. Это не удалось, поскольку эти разделы не имели эквивалента SQL. Я в конечном итоге использовал .Cast вместо этого, который, похоже, также решает проблему.

Ответ 7

В моем случае я неправильно объявил свойство Storage в атрибуте Column класса Linq2SQL

    [Column(Storage = "_Alias", DbType = "NVarChar(50)")]
    public string UserAlias

Ответ 8

У меня была такая же проблема, но с наследованием Я определил класс в сборке A и подкласс в сборке B после того, как я добавил атрибут ниже в сборку А, проблема решена:

[assembly: SecurityRules(SecurityRuleSet.Level1, SkipVerificationInFullTrust = true)]

Ответ 9

Я столкнулся с этой ошибкой, используя "Динамическую структуру доступа к данным" Пассивная библиотека. Источником ошибки была строка 100 в файле DynamicDatabase.cs.

databaseDetectors = (databaseDetectors ?? Enumerable.Empty<DatabaseDetector>()).DefaultIfEmpty(new DatabaseDetector());

Я изменил эту строку кода на:

databaseDetectors = (databaseDetectors ?? Enumerable.Empty<DatabaseDetector>()).DefaultIfEmpty(new DatabaseDetector()).OfType<IDatabaseDetector>();

Это разрешило проблему. Я пошел вперед и разветкил проект и представил изменение оригинальному автору.

Спасибо, Джейсон Бейкер, за то, что вы указали решение в своем первоначальном вопросе.

С другой стороны, оригинальная библиотека отлично работала на моем локальном компьютере и на Rackspace VPS, но когда я переместил один и тот же код в общую среду хостинга (GoDaddy и Rackspace Cloud Sites), я начал получать "Operation can дестабилизировать ошибку времени выполнения.

Ответ 10

Я предполагаю, что Linq to Sql может не поддерживать кастинг при переводе в sql-инструкцию.