Dynamically get class attribute value from type
Asked Answered
D

2

11

I'm trying to write a method that finds all types in an assembly with a specific custom attribute. I also need to be able to supply a string value to match on. The caveat is that I would like to be able to run this on any class and return any value.

For example: I would like to execute a call like this

Type tTest = TypeFinder.GetTypesWithAttributeValue(Assembly.Load("MyAssembly"), typeof(DiagnosticTestAttribute), "TestName", "EmailTest");

My method so far looks like this:

public static Type GetTypesWithAttributeValue(Assembly aAssembly, Type tAttribute, string sPropertyName, object oValue)
{
    object oReturn = null;
    foreach (Type type in aAssembly.GetTypes())
    {
        foreach (object oTemp in type.GetCustomAttributes(tAttribute, true))
        {
            //if the attribute we are looking for matches
            //the value we are looking for, return the current type.
        }
    }
    return typeof(string); //otherwise return a string type
}

My Attribute looks like this:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class DiagnosticTestAttribute : Attribute
{
    private string _sTestName = string.Empty;

    public string TestName
    {
        get { return _sTestName; }
    }
    public DiagnosticTest(string sTestName)
    {
        _sTestName = sTestName;
    }
}

For those familiar with expressions, I would really like to be able to make a call like:

TypeFinder.GetTypesWithAttributeValue<DiagnosticTestAttribute>(Assembly.Load("MyAssembly"), x=> x.TestName, "EmailTest");

Where the expression uses my generic type to select the property that I'm looking for.

Doddering answered 21/1, 2013 at 17:2 Comment(0)
R
14

This should work:

public static Type GetTypeWithAttributeValue<TAttribute>(Assembly aAssembly, Func<TAttribute, object> pred, object oValue) {
  foreach (Type type in aAssembly.GetTypes()) {
    foreach (TAttribute oTemp in type.GetCustomAttributes(typeof(TAttribute), true)) {
      if (Equals(pred(oTemp), oValue)) {
        return type;
      }
    }
  }
  return typeof(string); //otherwise return a string type
}

Or even nicer:

public static Type GetTypeWithAttributeValue<TAttribute>(Assembly aAssembly, Predicate<TAttribute> pred) {
  foreach (Type type in aAssembly.GetTypes()) {
    foreach (TAttribute oTemp in type.GetCustomAttributes(typeof(TAttribute), true)) {
      if (pred(oTemp)) {
        return type;
      }
    }
  }
  return typeof(string); //otherwise return a string type
}

This is how the invocation looks like:

  GetTypeWithAttributeValue<DefaultValueAttribute>(Assembly.GetCallingAssembly(), attribute => attribute.Value,
                                                    "string");

and this one respectively:

  GetTypeWithAttributeValue<DefaultValueAttribute>(Assembly.GetCallingAssembly(),
                                                    attribute => attribute.Value == "string");
Romy answered 21/1, 2013 at 17:18 Comment(2)
This worked flawlessly. I had to change the assembly as I was calling it from a different one but it works great. Thanks a bunch.Doddering
if i could give you more cred i would ;-)Abode
O
2

Long ago I've developed some helper methods to extract a property name from an expression,

I think it would be useful to you.

public static string Item<TItem, TMember>(this TItem obj, Expression<Func<TItem, TMember>> expression)
{
    if (expression.Body is MemberExpression)
    {
        return ((MemberExpression)(expression.Body)).Member.Name;
    }
    if (expression.Body is UnaryExpression)
    {
        return ((MemberExpression)((UnaryExpression)(expression.Body)).Operand).Member.Name;
    }
    if (expression.Body is ParameterExpression)
    {
        return expression.Body.Type.Name;
    }
    throw new InvalidOperationException();
}

Check out this file for more.

Overhaul answered 21/1, 2013 at 17:13 Comment(1)
That is helpful. As soon as I can figure out how to extract the value out of an attribute of an instance class that should help me create a nice interface for my method. Thanks!Doddering

© 2022 - 2024 — McMap. All rights reserved.