Attributes in C#
February 20, 2006 10:47 AM   Subscribe

Attributes in .NET (C#): From within a class, how do I find all the methods marked with an attribute and fire those methods?

I've found a number of links on attributes in C#, but they all show how to mark items in a class with an attribute and then look that info up from a small console application. I've managed to create an attribute (amazing, I know), but what I want to do is create a method in an abstract parent class that will fire all methods in a sub-class marked with my shiny new attribute. And that part's not happening.
posted by yerfatma to Computers & Internet (9 answers total)
 
Best answer: One way to do this is to use the Type.FindMembers method together with a custom MemberFilter. Sample code that does this follows. Sorry for the lousy formatting, but I couldn't figure out how to make tabs work properly.

using System;
using System.Reflection;

namespace AttributeTester
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Class1 c = new Class1();
c.GetMyAttributes();
}

public void Test1(int a)
{
}

[MyAttribute]
public void Test3(int a)
{
}

public void GetMyAttributes()
{
MemberInfo[] members = typeof(Class1).FindMembers(
MemberTypes.All,
BindingFlags.Instance | BindingFlags.Public,
new MemberFilter(FilterMembersByAttributeType),
typeof(MyAttribute));

foreach (MemberInfo mi in members)
{
Console.WriteLine(mi.Name);
}
}

private static bool FilterMembersByAttributeType(MemberInfo info, object state)
{
Type desired_attribute_type = (Type) state;
object[] attrs = info.GetCustomAttributes(desired_attribute_type, false);
return (0 < attrs.length);br> }
}

[AttributeUsage(AttributeTargets.Method)]
class MyAttribute : Attribute
{
}
}

posted by chos at 12:41 PM on February 20, 2006


I hate to presuppose, but make sure that your purpose wouldn't be better suited by another approach, such as an implementation of the command pattern or the use of delegates.
posted by feloniousmonk at 12:52 PM on February 20, 2006


Response by poster: No no, presuppose away. I'm just being lazy. chos, your answer kind of echoes the code I was able to find online. How would I do

Class1 c = new Class1();
c.GetMyAttributes();

from within Class1? typeof(this).FindMembers doesn't seem right/ work.
posted by yerfatma at 12:58 PM on February 20, 2006


Best answer: Right, typeof(this) isn't supported because typeof() only takes type/class names as opposed to specific instances, of which 'this' is one. You can use this.GetType() (or just GetType() for brevity).

MemberInfo[] members = GetType().FindMembers(...)

That seems to work for me.
posted by chos at 2:36 PM on February 20, 2006


No no, presuppose away. I'm just being lazy.

Just a general observation. People seem to avoid built in language craziness in favor of all kind of nonsensical OO/paterns stuff. If the language supports something like the command pattern, you should use it, rather then making your own gonzo system that it no one knows and requires a shitload of code to work with.
posted by delmoi at 7:03 PM on February 20, 2006


Response by poster: Fair enough. I'm trying to force something akin to an MVC (well, MVP, I guess) onto .NET1, though, more honestly, I'm aping Rails. Right now my models just have a series of methods to validate the various properties. I'm calling all of them explicitly in a wrapper method before I allow an Insert or Update to go through. What I'm trying to do is mark the various methods with an attribute so I don't have to have that wrapper method in every object.

I don't know if that's a good idea or not; how would the command pattern apply here?

1. Without using the UIP block or the other MVC approaches in .NET as they seem over-engineered for what I want to do. I'm giving Monorial a miss too in case you're wondering.
posted by yerfatma at 4:40 AM on February 21, 2006


Response by poster: I've tried to knead the code into place, but no joy. Here's what I have (with my tweaks in bold):

protected bool ValidateAttributes()
{
MemberInfo[] members = GetType().FindMembers(MemberTypes.All, BindingFlags.Default, new MemberFilter(FilterMembersByAttributeType), typeof(Core.MetaInfo.MethodValidationAttribute));
return false;
}

private static bool FilterMembersByAttributeType(MemberInfo info, object state)
{
Type desired_attribute_type = (Type)state;
object[] attrs = info.GetCustomAttributes(desired_attribute_type, false);
return (0 < attrs.length);br> }


The weird thing is the code never enters FilterMembersByAttributeType (I don't know if that's just a "feature" of a delegate): breakpoints inside it never get hit, stepping through the code never goes into the method. What am I totally missing here?
posted by yerfatma at 5:33 AM on February 21, 2006


Best answer: Ah, I've encountered that same problem before. The reason it's not entering your custom delegate is that it's never getting called (generally, you can set breakpoints inside of delegates just like you can with any other method).

Contrary to what you might expect, BindingFlags.Default specifies no bindings, as opposed to all of them. You have to be more explicit and specify what you are looking for, for example using BindingFlags.Instance, Public, Static, etc.
posted by chos at 7:47 AM on February 21, 2006


Response by poster: Thanks for all your help. I got it working by changing the flags (I'd originally been looking for BindingFlags.Private without realizing that wouldn't catch protected methods so they named it NonPublic instead). Once I changed the flag, I looped over the returned array like this:

foreach (MethodBase modelValidator in members)
{
modelValidator.Invoke(this, null);
}


Not sure if that's the proper cast, but it is doing what I want. Thanks again.
posted by yerfatma at 8:28 AM on February 21, 2006


« Older Robot Rock   |   Should I get a british passport? Newer »
This thread is closed to new comments.