views:

80

answers:

5

Take this sample class as an example:

    [AttributeUsage(AttributeTargets.All, AllowMultiple=true)]
public class BugFixAttribute : System.Attribute
{
    public int BugId { get; private set; }
    public string Programmer { get; private set; }
    public DateTime Date { get; private set; }
    public string Comments { get; set; }
    public string RefersTo { get; set; }

    public BugFixAttribute(int bugId = 0, string programmer = "")
    {
        this.BugId = bugId;
        this.Programmer = programmer;
        Date = DateTime.Now;
    }
}

And I want to recuse through the properties to use like:

object[] attr = info.GetCustomAttributes(typeof(BugFixAttribute), false);
foreach (object attribute in attr)
{
    BugFixAttribute bfa = (BugFixAttribute) attribute;
    Debug.WriteLine(string.Format("\nBugId: {0}", bfa.BugId));
    Debug.WriteLine(string.Format("Programmer: {0}", bfa.Programmer));
    //...
}

Because what I need to do is to print these to a file. So how can I recurse through the properties instead of doing the Debug.WriteLine() through all of them, is there a way or do I have to write it out.

+4  A: 

Yes, if you use reflection:

Type t = bfa.GetType();
PropertyInfo[] properties = t.GetProperties();
foreach(var prop in properties)
{
    Debug.WriteLine(string.Format("{0}: {1}", prop.Name,prop.GetValue(bfa,null)));
}

This will print the name and value of all public properties in bfa. You can check the CanRead property on a PropertyInfo to check if it can be read (ie. if it declares a getter). The example will fail if one of the properties are read-only or is indexed - if this can occur, you need to check for it in the code.

driis
A: 

If I read the question correctly, you're looking for a simpler way to write out the class information, right? You've got two options:

  1. reflection, for a highly generic solution that will prolly output way too much information (assuming this is java - or .NET which I've been told is very much the same...)
  2. define the toString() method, and call Debug.WriteLine(bfa)

Solution 1 is probably way overkill. You'll probably get output for stuff you don't want, and you'll not be able to get private values.

Solution 2 is the simple way.

public class BugFixAttribute : System.Attribute
{
 ...

 public String toString(){
   return string.Format("\nBugId: {0}\nProgrammer: {1}", this.BugId, this.Programmer));
 }
}
atk
I wouldn't say it's overkill to use reflection, it's like 30 seconds of code, and you can get private members. Still, ToString() is still a good option if his requirements fit, but i'm not sure they do.
Paul Creasey
@Paul Creasey: You're entirely right that it's dependent on his requirements. And that it's not all that much code. I'm thinking overkill in terms of output that'll be dumped if other objects are used, rather than in lines of code. It might also be a performance hit - IIRC, reflection is slow. Also, I'm surprised that reflection would be able to access private data - that would seem to violate the purpose of marking members as private.
atk
A: 
foreach (var (BugFixAttribute)attribute in attr)
{
    foreach(PropertyInfo prop in attribute.GetType().GetProperties())
    {
        Debug.WriteLine(string.Format("{0}: {1}", prop.name,prop.GetValue(attribute,null));
    }
}
Paul Creasey
+6  A: 

I would suggest that this is probably not a great use for Attributes, as it muddies up the meta attached to the code. If you want to standardize a way to get at this sort of information regarding bug fixes, I would suggest coming up with an XML Comment Tag, and then turning on XML Comments for your project, and using that instead.

Example Syntax:

/// <summary>This Method Does Something</summary>
/// <BugFix BugId="1234" Programmer="Bob" Date="2/1/2010">Fix Comments</BugFix>
public void MyMethod()
{
    // Do Something
}
Nick
then a simple xpath would get everything you needed, but production code would be unfettered. +1
Rob Fonseca-Ensor
+1 for being polite. me--> attributes for inert transient meta... what!? here is your pink slip.
Sky Sanders
+2  A: 

I love Linq for this kind of thing

var props = from b in info.GetCustomAttributes(typeof(BugFixAttribute), false)
            from p in b.GetType().GetProperties()
            select new { 
                   Name = p.Name,
                   Value = p.GetValue(p.GetValue(b, null))
                   };

foreach(var prop in props)
{
    Debug.WriteLine(string.Format("{0}: {1}", prop.Name, prop.Value));
}
pdr