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

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

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

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

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, кажется, предполагает, что это проблема безопасности типов, но я не вижу, где предыдущий код был небезопасным.

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

10 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Мое решение: запустить живой сайт на.NET4

`Я добавил в файл web.config в раздел System.Security.VerificationException: " Операция может дестабилизировать время выполнения ". не идет за мной.

<system.Web>
<trust level="Full"/>

Будет ли сбой, если вы измените это:

select new SomeObject { ... } as ISomeTable;

к этому:

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

?

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

Я столкнулся с этой ошибкой при использовании пассивной библиотеки"Динамический каркас доступа к данным". Источником ошибки была строка 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), я начал получать сообщение "Операция может дестабилизировать среду выполнения. " ошибка.

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

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

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

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

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

Я думаю, что Linq to Sql может не поддерживать приведение при переводе в оператор SQL.

Другие вопросы по тегам