Примечание. Следующий код действительно работает нормально, но показывает сценарий, который не работает в моем собственном решении. См. Нижнюю часть этого сообщения для получения дополнительной информации.
С этими классами:
public class MainType {
public static readonly MainType One = new MainType();
public static readonly MainType Two = SubType.Two;
}
public sealed class SubType : MainType {
public new static readonly SubType Two = new SubType();
}
Получить поля One
и Two
:
List<FieldInfo> fieldInfos = typeof(MainType)
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Where(f => typeof(MainType).IsAssignableFrom(f.FieldType))
.ToList();
Наконец, получите их значения:
List<MainType> publicMainTypes = fieldInfos
.Select(f => (MainType) f.GetValue(null))
.ToList();
В LinqPad или в простом классе unit test с указанным выше кодом все работает нормально. Но в моем решении, где у меня есть некоторые модульные тесты, которые хотят работать со всеми экземплярами этих полей, GetValue
отлично работает, чтобы возвращать поля родительского типа, но там, где предполагается, что родительские поля имеют экземпляры подтипа, они всегда вместо этого дайте null
! (Если это произошло здесь, окончательный список будет { One, null }
вместо { One, Two }
.) Класс тестирования находится в другом проекте из двух типов (каждый в своем собственном файле), но я временно сделал все общедоступным. Я сбросил точку останова и просмотрел все, что я могу проверить, и сделал эквивалент fieldInfos[1].GetValue(null)
в выражении Watch, и на самом деле он возвращает null, несмотря на то, что в моем основном классе есть строка точно так же, как второй из MainType
выше.
Что не так? Как получить все значения полей подтипа? Как это возможно, чтобы они могли возвращать null без ошибки?
По теории, что по какой-то причине класс подтипа не был статически построен из-за доступа через отражение, я пробовал
System.Runtime.CompilerServices.RuntimeHelpers
.RunClassConstructor(typeof(SubType).TypeHandle);
вверху перед запуском, но это не помогло (где SubType
- фактический класс подтипа в моем проекте).
Я буду продолжать подключаться, пытаясь воспроизвести это в простом случае, но на данный момент у меня нет идей.
Дополнительная информация
После путаницы код начал работать. Теперь он снова не работает. Я работаю над воспроизведением того, что инициировало запуск кода.
Примечание. Ориентация .Net 4.6.1 с использованием С# 6.0 в Visual Studio 2015.
Репродукция проблемы доступна
Вы можете играть с рабочей (неудачной) урезанной версией моего сценария, загрузив этот несколько минимальный рабочий пример проблемы в github.
Отладить модульные тесты. Когда возникает исключение, сделайте шаг, пока не дойдете до строки 20 GlossaryHelper.cs и не увидите возвращаемое значение GetGlossaryMembers
на вкладке Locals
. Вы можете видеть, что индексы с 3 по 12 являются нулевыми.