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 controlle
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);
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"));
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;
}
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()
{
}
}
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 ;
}
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);
}
}