9

Possible Duplicate:
Finding all classes with a particular attribute

In an assembly I would like to get all instances of a particular class attribute. In other words I would like to have the list of classes that have a specific attribute.

Normally you would have a class for which you can fetch the attribute using the GetCustomAttributes method.

Is it possible to have a list of who has a particular attribute?

Community
  • 1
  • 1
mathk
  • 7,973
  • 6
  • 45
  • 74

4 Answers4

4
public static IEnumerable<Type> GetTypesWithMyAttribute(Assembly assembly)
{
    foreach(Type type in assembly.GetTypes())
    {
        if (Attribute.IsDefined(type, typeof(MyAttribute)))
            yield return type;
    }
}

Or:

public static List<Type> GetTypesWithMyAttribute(Assembly assembly)
{
    List<Type> types = new List<Type>();

    foreach(Type type in assembly.GetTypes())
    {
        if (type.GetCustomAttributes(typeof(MyAttribute), true).Length > 0)
            types.Add(type);
    }

    return types;
}

Linq VS my method benchmark (100000 iterations):

Round 1
My Approach:     2088ms
Linq Approach 1: 7469ms
Linq Approach 2: 2514ms

Round 2
My Approach:     2055ms
Linq Approach 1: 7082ms
Linq Approach 2: 2149ms

Round 3
My Approach:     2058ms
Linq Approach 1: 7001ms
Linq Approach 2: 2249ms

Benchmark code:

[STAThread]
public static void Main()
{
    List<Type> list;

    Stopwatch watch = Stopwatch.StartNew();

    for (Int32 i = 0; i < 100000; ++i)
        list = GetTypesWithMyAttribute(Assembly.GetExecutingAssembly());

    watch.Stop();

    Console.WriteLine("ForEach: " + watch.ElapsedMilliseconds);

    watch.Restart();

    for (Int32 i = 0; i < 100000; ++i)
        list = GetTypesWithMyAttributeLinq1(Assembly.GetExecutingAssembly());

    Console.WriteLine("Linq 1: " + watch.ElapsedMilliseconds);

    watch.Restart();

    for (Int32 i = 0; i < 100000; ++i)
        list = GetTypesWithMyAttributeLinq2(Assembly.GetExecutingAssembly());

    Console.WriteLine("Linq 2: " + watch.ElapsedMilliseconds);

    Console.Read();
}

public static List<Type> GetTypesWithMyAttribute(Assembly assembly)
{
    List<Type> types = new List<Type>();

    foreach (Type type in assembly.GetTypes())
    {
        if (Attribute.IsDefined(type, typeof(MyAttribute)))
            types.Add(type);
    }

    return types;
}

public static List<Type> GetTypesWithMyAttributeLinq1(Assembly assembly)
{
    return assembly.GetTypes()
               .Where(t => t.GetCustomAttributes().Any(a => a is MyAttribute))
               .ToList();
}

public static List<Type> GetTypesWithMyAttributeLinq2(Assembly assembly)
{
    return assembly.GetTypes()
               .Where(t => Attribute.IsDefined(t, typeof(MyAttribute)))
               .ToList();
}
Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
2

You can do this using reflection. This will get you a List<Type> of all types within the current assembly that have MyAttribute.

using System.Linq;
using System.Reflection;

// ...

var asmbly = Assembly.GetExecutingAssembly();
var typeList = asmbly.GetTypes().Where(
        t => t.GetCustomAttributes(typeof (MyAttribute), true).Length > 0
).ToList();
Rudi Visser
  • 21,350
  • 5
  • 71
  • 97
  • Yes ok, that is what I wanted to avoid. Having to loop over all Class of a paticular asssembly is not quite nice. But if that is the only solution. – mathk Jan 21 '13 at 14:21
  • @mathk Unfortunately it is; It shouldn't be that slow to perform the check per type, though. If you're going to be reusing this check in multiple places, you could always cache the results. – Rudi Visser Jan 21 '13 at 14:22
  • I would use this only once at the beginning of the application. I am not concern by speed. But asking the runtime to create all does reification it is something I am not quite fan of. Some static method on Attribute class like: `GetAllType`, or `GetAllProperties`, ... would have been nicer. – mathk Jan 21 '13 at 14:32
  • @mathk I see, but if you're only running it at startup it may not be that much of a performance issue :) BTW, you could always implement this static method that would still end up using this code as a backing. Do you want an example? – Rudi Visser Jan 21 '13 at 14:34
  • Yes you are correct speed is not an issue. The little down side I found is: like you have to do a surgery on a heart but in other to get to the heart you have to scan over all other organ. It is not very clean, no pun intended. What if reflection was not allowed as it expose too mush details of the runtime. – mathk Jan 21 '13 at 14:42
  • @mathk Unfortunately Reflection is the *only* way to access attributes. What you may want to look at instead, is tracking the classes (in the attribute constructor) that the attribute has been applied to. But this is somewhat hacky, as you'd need to take the Type you're decorating as a parameter on the attribute, and maintain an external list. – Rudi Visser Jan 21 '13 at 14:48
1
var list = asm.GetTypes()
            .Where(t => t.GetCustomAttributes().Any(a => a is YourAttribute))
            .ToList();
I4V
  • 34,891
  • 6
  • 67
  • 79
0

With no code examples, one assumes you have a List<Type> or an Assembly.

public List<Type> TypesWithAttributeDefined(Type attribute)
{
  List<Type> types = assembly.GetTypes();
  return types.Where(t => Attribute.IsDefined(t, attribute)).ToList();
}
LukeHennerley
  • 6,344
  • 1
  • 32
  • 50