Andy Allison
Andy Allison

Reputation: 765

C# Extension method for checking attributes

Sorry if this is a stupid noob question please be gentle with me I'm trying to learn...

I want to test against the attribute methods of things like models and controllers. Mostly to make sure they have the right attrbute ie Required. But i'm also using this as an experiment with extension methods and Lambdas.

What I'd like is a method that when implimented looks some thing like

Controller controller = new Controller();
controller.MethodName(params).HasAttribute<AttributeName>();

Iveused extension methods a little but not to this degree.. I'm sure this should be simple enough to do but cant seem to get my generics etc correct.

Upvotes: 13

Views: 3165

Answers (6)

Steven
Steven

Reputation: 172825

Perhaps you are looking for this:

Controller controller = new Controller();
bool ok = controller.GetMethod(c => c.MethodName(null, null))
    .HasAttribute<AttributeName>();

What's nice about writing it like this is that you have fully compile time support. All other solutions thus far use string literals to define the methods.

Here are the implementations of the GetMethod and HasAttribute<T> extension methods:

public static MethodInfo GetMethod<T>(this T instance,
    Expression<Func<T, object>> methodSelector)
{
    // Note: this is a bit simplistic implementation. It will
    // not work for all expressions.
    return ((MethodCallExpression)methodSelector.Body).Method;
}

public static MethodInfo GetMethod<T>(this T instance,
    Expression<Action<T>> methodSelector)
{
    return ((MethodCallExpression)methodSelector.Body).Method;
}

public static bool HasAttribute<TAttribute>(
    this MemberInfo member) 
    where TAttribute : Attribute
{
    return GetAttributes<TAttribute>(member).Length > 0;
}

public static TAttribute[] GetAttributes<TAttribute>(
    this MemberInfo member) 
    where TAttribute : Attribute
{
    var attributes = 
        member.GetCustomAttributes(typeof(TAttribute), true);

    return (TAttribute[])attributes;
}

Upvotes: 19

Jerod Houghtelling
Jerod Houghtelling

Reputation: 4867

Usage:

bool hasAttribute = controller.HasMethodAttribute<TestAttribute>( "Test" )

Extension:

public static bool HasMethodAttribute<TAttribute>( this object obj, string methodName )
{
    Type type = obj.GetType();

    MethodInfo method = type.GetMethod( methodName );
    if( method == null )
    {
        throw new ArgumentException( string.Format( 
            "Method '{0}' not found on object '{1}'", methodName, type.Name ) );
    }

    return method.GetCustomAttributes( typeof( TAttribute ), true ).Length > 0 ;
} 

Upvotes: 1

theburningmonk
theburningmonk

Reputation: 16061

You can check whether a method has a particular attribute by doing this:

typeof(Controller).GetMethod("MethodName").GetAttributes<AttributeName>().Any();

In terms of the extension method itself, provided that you're looking for an extension method on the Controller type, how about something like this:

public static bool HasAttribute<A>(this Controller controller, string methodName)
{
   return controller.GetType().GetMethod(methodName).GetCustomAttributes(typeof(A), true).Any();
}

Remember, extension methods are invoked on an instance, so to use this you still need an instance of Controller:

var controller = new Controller();
Assert.IsTrue(controller.HasAttribute<AttributeName>("Method1"));

Upvotes: 0

BlueMonkMN
BlueMonkMN

Reputation: 25601

Can't quite do exactly that with extension methods, but this is close:

public static class Program
{
  static void Main(string[] args)
  {
     Controller c1 = new Controller();
     Action a1 = c1.Method1;
     Console.WriteLine(a1.HasAttribute<Controller.TestAttribute>());
  }

  public static bool HasAttribute<T>(this Action method)
  {
     return method.Method.GetCustomAttributes(typeof(T), false).Any();
  }
}

class Controller
{
  [AttributeUsage(AttributeTargets.Method)]
  public class TestAttribute : System.Attribute
  {
  }

  [Test()]
  public void Method1()
  {
  }
}

Upvotes: 1

Ryan Brunner
Ryan Brunner

Reputation: 14851

I don't think you'll be able to implement that exactly as you described. The MethodName(params) part of your statement will actually execute the method, returning whatever the method returns, and not information about the method.

What you want to do is pass in a MethodInfo into your extension class, using reflection. So instead of your example, you'd probably end up with something like:

 controller.GetType().GetMethod(methodName).HasAttribute<AttributeName>();

You could probably simplify this down to a single extension method on the controller class by encapsulating GetType().GetMethod(), like so:

 controller.MethodHasAttribute(methodName, attributeName);

Upvotes: 1

Chris
Chris

Reputation: 2477

You're looking for the Reflection class - it allows you to examine a passed object.

But frankly other than a learning exercise this is what Interfaces exist for, if you want there to be a field called Required in a model, or a method called IsRequired in a controller than implement in an interface and require that interface be implemented.

Specifically for attributes see here:

Type t = something;
System.Console.WriteLine("Author information for {0}", t);
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // reflection

foreach (System.Attribute attr in attrs)
{
    if (attr is Author)
    {
        Author a = (Author)attr;
            System.Console.WriteLine("   {0}, version {1:f}", a.GetName(), a.version);
    }
}

Upvotes: -1

Related Questions