GetCustomAttribute возвращает null во время выполнения на .NET5

#c# #reflection #attributes #runtime #.net-5

Вопрос:

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

Я пытаюсь получить фактический объект CustomAttribute. Во время отладки в net framework код возвращает значение. Выполнение кода на .Net5 возвращает null

Редактировать после некоторого изучения документации:

.NET Framework версии 2.0 предоставляет новый контекст загрузки, контекст только для отражения, который можно использовать для проверки кода, который не может быть загружен для выполнения.

https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/accessing-custom-attributes

Редактировать # 2 Причина в том, что я пытаюсь получить объект во время выполнения, и, как написано в приведенной выше цитате documentaion, атрибут, а также любой другой контекст только для отражения во время выполнения, не могут быть загружены, и метод возвращает null.

Есть ли какое-либо другое решение, кроме использования system.reflection для получения фактического объекта атрибута во время выполнения?

Инициализация словаря

         var ass = Assembly.LoadFile(Path.GetFullPath("MyInterface.dll"));
        var asss = Assembly.GetExecutingAssembly();
        var apiInterfaces = ass.DefinedTypes.Where(x => x.IsInterface amp;amp; x.CustomAttributes != null amp;amp; x.CustomAttributes.Any(z => z.AttributeType.FullName != null amp;amp; z.AttributeType.FullName.Equals(typeof(ApiInterfaceDescriptorAttribute).FullName)));
        
 

Атрибут:

 [AttributeUsage(AttributeTargets.Interface)]
public class ApiInterfaceDescriptorAttribute : Attribute
{
    public string ApiUsageName { get; }

    public ApiInterfaceDescriptorAttribute(string apiUsageName)
    {
        ApiUsageName = apiUsageName;
    }
}
 

Пример интерфейса

 [ApiInterfaceDescriptor("powercontrol")]
public interface IMyInterface 
{
   [ApiMethodDescriptor(ApiExposureLevel.Basic, "a-method...")]
    void SomeMethod();
}
 

Пробная версия для получения атрибута

 public class ApiDetector
{
    private Dictionary<Type, List<MethodInfo>> _apiDictionary = new Dictionary<Type, List<MethodInfo>>();
    public void LoadApiElements()
    {
        var apiKeyDesriptor = key.GetCustomAttribute(typeof(ApiInterfaceDescriptorAttribute)) as ApiInterfaceDescriptorAttribute;
            _apiDetector.Add(new ApiDataObjectDescriptor { Name = key.Name, ApiUsageName = apiKeyDesriptor?.ApiUsageName, Type = key });
    }

}
 

когда я запускал этот код локально, я получал экземпляр:
введите описание изображения здесь

Выполнение кода на удаленной машине .Net5 возвращает null:

введите описание изображения здесь

Любая помощь будет приветствоваться. Заранее спасибо!

Комментарии:

1. Этот минимальный код , похоже, отлично работает в .NET5 и 6. Что вы подразумеваете под «удаленной машиной» (вы делаете это с помощью удаленной отладки)? Вы уверены, что это ошибка .NET5?

2. В GetCustomAttribute есть второй аргумент — bool inherit . Не уверен, связано ли это с вашей проблемой, но вы можете рассмотреть возможность передачи a true туда.

3. @Vic F — я тоже пробовал со вторым аргументом…

4. @NPras — Я обновляю сообщение, оно не связано с удаленной машиной, я также проверил локально в папке отладки .Net 5 bin со стандартной отладкой и получил те же результаты. также я добавил инициализацию словаря, это может быть разница между минимальным кодом. есть идеи?

5. Вы проверили, действительно ли словарь содержит что-либо к этому моменту? Возможно, выполните метод, который заполняет dict, и посмотрите, правильно ли он загружал данные.

Ответ №1:

Основной причиной является вызов Assembly .Загрузочный файл. Этот метод всегда загружает указанную сборку в свой собственный AssemblyLoadContext . (Подробнее о контексте загрузки сборки).

Это означает, что у вас есть сборка, загруженная в контекст загрузки LoadFile (одна копия), и у меня есть прямая ссылка на нее из вашего основного кода, который загрузит ее в контекст загрузки по умолчанию (вторая копия). Хотя файл сборки точно такой же, для среды выполнения эти две копии являются разными сборками, и все типы из них будут рассматриваться как разные типы.

изменение метода загрузки сборки на:

 Assembly.GetAssembly(typeof(MyType));
 

решили проблему.

спасибо витеку-карасу из службы поддержки Microsoft.