Обнаружение атрибута в сборке без предварительной загрузки в домен .NET

Интересует возможно ли узнать наличие определенного атрибута во внешней библиотеке без загрузки библиотеки в домен. Есть к примеру две сборки:

// Основная сборка
namespace FirstAsm
{
    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
    public sealed class InitLoaderAttribute : Attribute
    {
        public Type InitType { get; }
        public InitLoaderAttribute(Type initType)
        {
            InitType = initType;
        }
    }
    ...
}

// Внешняя сборка
[assembly: InitLoader(typeof(MyClass))]
namespace SecondAsm
{
    ...
}

Стандартного API для таких целей я не нашел. AppDomain.Load не подойдет, т.к. мне прежде всего нужно узнать наличие нужного атрибута. Может есть какие советы


Ответы (1 шт):

Автор решения: MSDN.WhiteKnight

В комментариях правильно указали на несколько способов, которые позволяют сделать это:

  • Assembly.ReflectionOnlyLoad (.NET Framework)
  • System.Reflection.Metadata (.NET Standard 1.1+)
  • System.Reflection.MetadataLoadContext (.NET Standard 2.0+)

В .NET Core проще всего воспользоваться третьим способом. Подключаем пакет System.Reflection.MetadataLoadContext. Вот так мы можем прочитать значение атрибута сборки:

using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;

namespace MetadataLoadContextSample
{
    class Program
    {
        static int Main(string[] args)
        {
            string inputFile = @"C:\Test\Example.dll"; //проверяемая сборка
            string attrFile = @"C:\Test\InitLoader.dll"; //сборка с определением атрибута

            string[] runtimeAssemblies = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");                        
            var paths = new List<string>(runtimeAssemblies);
            paths.Add(inputFile);
            paths.Add(attrFile);
            var resolver = new PathAssemblyResolver(paths);
            var context = new MetadataLoadContext(resolver);

            using (context)
            {                
                Assembly assembly = context.LoadFromAssemblyPath(inputFile);

                foreach (CustomAttributeData attr in assembly.GetCustomAttributesData())
                {
                    if (String.Equals(attr.AttributeType.Name, "InitLoaderAttribute", StringComparison.InvariantCulture))
                    {
                        Console.WriteLine(attr.ConstructorArguments[0].Value);
                    }
                }
            }

            Console.ReadLine();
            return 0;
        }
    }
}
→ Ссылка