Почему эта строка вызывает исключение VerificationException при работе в .NET 4? - PullRequest
19 голосов
/ 03 августа 2011

Помогите мне, ребята - почему этот код вызывает исключение VerificationException при запуске в .NET 4.0?

public  T parseEnum<T>(string value, T defaultValue) {
  //Removing the following lines fixes the problem
  if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
  return defaultValue;
}

Я запустил peverify на сборке .net 2.0 и получил следующее сообщение:

ImageResizer.Util.Utils :: parseEnum [T]] [смещение 0x0000000A] Параметр this для вызова должен быть параметром this вызывающего метода.

Это вызывает сообщение VerificationException: Operation could destabilize the runtime при запуске кода со средним доверием.

Я уже прочитал все похожие сообщения о переполнении стека, и ни один из них не применим к этому коду.

Есть ли что-то новое в дженериках, которое может сделать этот код каким-то недействительным?

1 Ответ

32 голосов
/ 03 августа 2011

Основной причиной ошибки является изменение подписи IsEnum.

В .NET 2.0 (и 3.0) IsEnum не был виртуальным методом :

public bool IsEnum { get; }

Сборка, выпущенная, чтобы назвать это:

call instance bool [mscorlib]System.Type::get_IsEnum()

В .NET 4.0 IsEnum - это виртуальный метод :

public virtual bool IsEnum { get; }

Вот та же самая линия сборки для 4.0:

callvirt instance bool [mscorlib]System.Type::get_IsEnum()

Ошибка, которую вы получаете, была добавлена ​​в peverify непосредственно перед выпуском 2.0 и предупреждает, когда виртуальный метод вызывается не виртуально.

Теперь peverify загружает ваш код, загружает .NET 4.0, а затем проверяет ваш код. Поскольку ваш код вызывает виртуальный метод (.NET 4.0) не виртуально, отображается ошибка.

Можно было бы подумать, что поскольку вы работаете с версией .NET 2.0, это должно быть хорошо, и для проверки будет загружена .NET 2.0 CLR. Это не так.

Edit:

Чтобы проверить это, я скачал .NET 2.0 SDK и попробовал peverify там. Это правильно проверяет код.

Таким образом, сообщение может выглядеть так: используйте peverify, который соответствует целевой структуре вашего кода.

Решение:

Кажется, что _Type интерфейс обеспечивает решение этой проблемы:

if (((_Type)typeof(T)).IsEnum) ...

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

Я подтвердил, что он работает с peverify независимо от того, нацелен ли вы на 2.0 или 4.0.

...