tags:

views:

627

answers:

3

The code below successfully recognizes internal classes which are decorated with my custom "Module" attribute, I load the assembly like this:

Assembly assembly = Assembly.GetExecutingAssembly();

However, when I load in an external module and look through its classes, it finds the classes in the external assembly but does not recognize the custom attributes:

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

What do I have to specify so that C# recognizes custom attributes in external .dlls the same as it does with the internal classes?

Here is the code that successfully runs through and recognizes internal classes decorated with my "Module" attribute:

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);
        }

    }
}

Here is my custom Mdoule attribute:

using System;

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

Here is a custom module:

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

How many instances of the ModuleAttribute class do you have defined across your assemblies?

It looks like you have one in DynamicAssembly2 and one in CustomModules ... in which case they are different types.

Your code in DynamicAssembly2 should use the attribute class defined in CustomModules (or both assemblies should load the attribute from a 3rd assembly).

Rob Walker
Yes, exactly, I had one in DynamicAssembly2 and one in CustomModules. I made a new project called "CustomAttributes" and referenced this from both projects, then it worked. Excellent, thanks.
Edward Tanguay
+2  A: 

I'm pretty sure that it doesn't distinguish... are you sure you are asking for the right attribute? As long as both projects reference the same ModuleAttribute, then typeof(ModuleAttribute) should work. Otherwise you'll need to first find the Type of the attribute you want (from Assembly.GetType()), and use that when calling GetCustomAttributes.

Marc Gravell
+1  A: 

Aloha

I've tested your code but couldn't get it to compile because the type ModuleAttribute must be known in both the Main program and the external dll. I assumed there were no references involved.

I did get it to work by introducing a reference.

Here's the class. This assembly holds a reference to DynamicAssembly

using System;    

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

Here's the code in 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);
        }

    }
}
edosoft