Как заставить C # распознавать пользовательские атрибуты во внешнем .dll? - PullRequest
2 голосов
/ 16 марта 2009

Код ниже успешно распознает внутренние классы, которые украшены моим собственным атрибутом "Модуль", я загружаю сборку следующим образом:

Assembly assembly = Assembly.GetExecutingAssembly();

Однако, когда я загружаю во внешний модуль и просматриваю его классы, он находит классы во внешней сборке, но не распознает пользовательские атрибуты :

Assembly assembly = Assembly.LoadFrom(@"c:\tests\modules\CustomModules.dll");

Что мне нужно указать, чтобы C # распознавал пользовательские атрибуты во внешних .dll так же, как и с внутренними классами?

Вот код, который успешно проходит и распознает внутренние классы, украшенные моим атрибутом «Модуль»:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace DynamicAssembly2
{
    class Program
    {
        static void Main(string[] args)
        {
            var modules = from t in GetModules()
                           select t;
            foreach (var module in modules)
            {
                ModuleAttribute[] moduleAttributes = GetModuleAttributes(module);
                Console.WriteLine(module.FullName);
                foreach (var moduleAttribute in moduleAttributes)
                {
                    Console.WriteLine(moduleAttribute.Description);
                }
            }
            Console.ReadLine();
        }

        public static IEnumerable<Type> GetModules()
        {
            //Assembly assembly = Assembly.LoadFrom(@"c:\tests\modules\CustomModules.dll");
            Assembly assembly = Assembly.GetExecutingAssembly();

            return GetAssemblyClasses(assembly)
                .Where((Type type) => {return IsAModule(type);});
        }

        public static IEnumerable<Type> GetAssemblyClasses(Assembly assembly)
        {
            foreach (Type type in assembly.GetTypes())
            {
                Console.WriteLine(type.FullName);
                yield return type;
            }
        }

        public static bool IsAModule(Type type)
        {
            return GetModuleAttribute(type) != null;
        }

        public static ModuleAttribute GetModuleAttribute(Type type)
        {
            ModuleAttribute[] moduleAttributes = GetModuleAttributes(type);
            Console.WriteLine(moduleAttributes.Length);
            if (moduleAttributes != null && moduleAttributes.Length != 0)
                return moduleAttributes[0];
            return null;
        }

        public static ModuleAttribute[] GetModuleAttributes(Type type)
        {
            return (ModuleAttribute[])type.GetCustomAttributes(typeof(ModuleAttribute), true);
        }

    }
}

Вот мой пользовательский атрибут Mdoule:

using System;

namespace DynamicAssembly2
{
    [AttributeUsage(AttributeTargets.Class)]
    public class ModuleAttribute : Attribute
    {
        public string Description { get; set; }
    }
}

Вот пользовательский модуль:

namespace DynamicAssembly2
{
    [Module(Description="This is the main customer class.")]
    class Customers
    {
    }
}

Ответы [ 4 ]

4 голосов
/ 16 марта 2009

Сколько экземпляров класса ModuleAttribute вы определили в своих сборках?

Похоже, у вас есть один в DynamicAssembly2 и один в CustomModules ... в этом случае они разных типов.

Ваш код в DynamicAssembly2 должен использовать класс атрибута, определенный в CustomModules (или обе сборки должны загружать атрибут из третьей сборки).

2 голосов
/ 16 марта 2009

Я почти уверен, что он не различает ... ты уверен, что просишь правильный атрибут? Пока оба проекта ссылаются на одно и то же ModuleAttribute, тогда typeof(ModuleAttribute) должно работать. В противном случае вам нужно сначала найти Type требуемого атрибута (от Assembly.GetType()) и использовать его при вызове GetCustomAttributes.

1 голос
/ 16 марта 2009

Aloha

Я протестировал ваш код, но не смог заставить его скомпилировать, потому что тип ModuleAttribute должен быть известен как в основной программе, так и во внешней dll. Я предположил, что не было никаких ссылок.

Я заставил его работать, введя ссылку.

Вот класс. Эта сборка содержит ссылку на DynamicAssembly

using System;    

namespace DynamicAssembly2
{
    [DynamicAssembly.Module(Description = "This is the main customer class.")]
    public class Customers
    {
    }
}

Вот код в DynamicAssembly:

using System.Reflection;

namespace DynamicAssembly
{
    [AttributeUsage(AttributeTargets.Class)]
    public class ModuleAttribute : Attribute
    {
        public string Description { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var modules = from t in GetModules()
                          select t;
            foreach (var module in modules)
            {
                ModuleAttribute[] moduleAttributes = GetModuleAttributes(module);
                Console.WriteLine(module.FullName);
                foreach (var moduleAttribute in moduleAttributes)
                {
                    Console.WriteLine(moduleAttribute.Description);
                }
            }
            Console.ReadLine();
        }

        public static IEnumerable<Type> GetModules()
        {
            Assembly assembly = Assembly.LoadFrom(@"C:\Temp\ClassLibrary1\bin\Debug\ClassLibrary1.dll");

            return GetAssemblyClasses(assembly)
                .Where((Type type) => { return IsAModule(type); });
        }

        public static IEnumerable<Type> GetAssemblyClasses(Assembly assembly)
        {
            foreach (Type type in assembly.GetTypes())
            {
                yield return type;
            }
        }

        public static bool IsAModule(Type type)
        {
            return GetModuleAttribute(type) != null;
        }

        public static ModuleAttribute GetModuleAttribute(Type type)
        {
            ModuleAttribute[] moduleAttributes = GetModuleAttributes(type);
            Console.WriteLine(moduleAttributes.Length);
            if (moduleAttributes != null && moduleAttributes.Length != 0)
                return moduleAttributes[0];
            return null;
        }

        public static ModuleAttribute[] GetModuleAttributes(Type type)
        {
            return (ModuleAttribute[])type.GetCustomAttributes(typeof(ModuleAttribute), true);
        }

    }
}
0 голосов
/ 14 декабря 2010

У меня была такая же проблема. Если бы атрибут был определен во внутреннем * cs, я мог бы получить атрибут, но если бы он был определен во внешнем dll, я бы просто получил null, когда запросил его (без ошибок), но и без ошибки компоновщика.

Очевидно, что пользовательский атрибут, определенный в DLL, и тот же пользовательский атрибут, определенный в локальном коде (* cs), будут успешно скомпилированы в одно приложение без каких-либо предупреждений о нескольких определениях (пространства имен идентичны). Я избавился от локального кода (* cs), исправил ссылки и все заработало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...