#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.