AccessViolationException при доступе к свойству mustoverride в библиотеке классов

Это немного сложно, но я попытаюсь объяснить это.

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

То, что у меня получилось, это:

Класс ConfigurationSectionBase является общим, принимая TConfElementCollection As {ConfigurationElementCollection, New} как ограничение типа.

Этот класс ConfigurationSectionBase содержит Public MustOverride Property Collection As TConfElementCollection.

Идея заключается в том, что в проекте, использующем библиотеку классов, они просто должны переопределить коллекцию и украсить ее атрибутом <ConfigurationProperty("CollectionName")>, например:

<ConfigurationProperty("CollectionName")>
Public Overrides Property Collection As DerivedConfigurationElementCollection
    Get
        Return TryCast(Me("CollectionName"), DerivedConfigurationElementCollection)
    End Get
    Set(value As DerivedConfigurationElementCollection)
        Me("CollectionName") = value
    End Set
End Property

Это отлично работает - в используемом приложении я мог бы создать раздел, а затем в моем классе обработчика конфигураций я мог бы позвонить

Dim section As DerivedSection = (TryCast(Config.GetSection("DerivedSection"), DerivedSection))
Dim coll as DerivedConfigurationElementCollection = section?.Collection

Итак, моя следующая мысль была причиной того, что абстрагировать также класс дескриптора Config и переместить его в базовый класс?

Это оказалось более сложным, но в итоге я получил следующий код в классе ConfigurationHandlerBase в DLL:

Protected Function GetCollection(Of TCollection As ConfigurationElementCollection, TSection As {ConfigurationSectionBase(Of TCollection), New})(sectionName as String) As TCollection
    Dim s As TSection = (TryCast(Config.GetSection(sectionName), TSection))
    Return s?.Collection ' AccessViolationException is thrown on this line

Чтобы попытаться диагностировать проблему, я создал свойство String так же, как Collection (MustOverride в классе ConfigurationSectionBase в DLL, переопределенном в используемом приложении), а затем попытался получить доступ к этому из класса библиотека - и опять же та же проблема.

Итак, я думаю, что проблема связана с MustOverride, а DLL-код не распознает, что класс Derived переопределил свойство.

Если вместо этого я возвращаю TSection из DLL-метода, то обращаюсь к свойству Collection в приложении, использующем DLL; Я могу получить доступ к коллекции.

Странно, если я поставил точку останова, Visual Studio довольно счастливо покажет мне содержимое свойства Collection, не выбрасывая никаких Исключений.

Кроме того, если я заменяю (TryCast(Config.GetSection(sectionName), TSection)) на new TSection(), я все равно получаю исключение AccessViolationException, поэтому он не имеет никакого отношения к тому, что я обращаюсь к файлу конфигурации, насколько я могу видеть.

Кто-нибудь сталкивался с этим раньше; или что могли бы сделать следующие шаги для устранения этого исключения?

Ответ 1

Вы являетесь жертвой ошибки генерации кода компилятора vb.net, он управляет кодом для метода ConfigurationHandlerBase.GetCollection(). Он ненадлежащим образом оптимизирует запрос getter свойства свойства Collection, используя ограниченный вызов. Самый простой способ увидеть это - запустить PEVerify.exe на сборке TestCollection.dll, хотя сообщение об ошибке выглядит для меня неправильным:

[IL]: Ошибка: [C:\temp\temp\TestClassLibrary\TestClassLibrary\bin\Debug\testclasslibrary.dll: TestClassLibrary.ConfigurationHandlerBase`1 [TDerivedConfigHandler]:: GetCollection [TCollection, TSection]] [offset 0x00000024] Аргумент 'this' для  ограниченный вызов должен иметь тип ByRef. 1 Ошибка Проверка testclasslibrary.dll

Поиск сообщения об ошибке, однако, приземляется на этот вопрос github.com. Отмечено, что исправлено 3 месяца назад, я думаю, что это был этот вопрос SO, который его отремонтировал. Это не всегда очевидно, когда такие исправления попадают на наши машины. Не сегодня.

Обходной путь, предложенный в проблеме github, не представляется эффективным. Простейшее обходное решение, которое я вижу, - это избегать оператора elvis и вернуться к основам, переписать:

   Dim coll As TCollection = s?.Collection
   Return coll

To:

   If s Is Nothing Then return Nothing Else Return s.Collection