1

I have a C# class that is used in my custom DB ORM tools, called DbFieldAttribute.

I place it over my field, like so:

[DbField("User_Id")]
public int UserId{ get; set; }

Challenge: From my attributes Constructor code, get the FieldInfo of the field it is associated with the attribute. In the case above, it would give me the FieldInfo for UserId.

Any help would be great. Thanks.

  • It's a property, not a field, so get all properties with reflection and check if each `PropertyInfo` has the desired custom attribute. – Jeppe Stig Nielsen Jul 19 '13 at 15:11
  • Attributes don't fire magically.. something has to fire them. You can pass a reference to the `PropertyInfo` through your attribute when you check for the existence of the attribute. – Simon Whitehead Jul 19 '13 at 15:12
  • Thanks. The attribute works with both Properties and Fields, and I accidentally showed one of the property types. –  Jul 19 '13 at 17:16
  • @Jeppe: get all the properties with reflection you say, but how do I even determine the object it was attached to, and then, how do I know if I'm looking at the write attribute? That was the core of the initial question –  Jul 19 '13 at 17:16
  • I'm not sure I have understood you correctly, but I was thinking you could do something like `typeof(TheClassYouHave).GetProperties.Where(pi => pi.GetCustomAttributes(typeof(DbFieldAttribute), false).Length != 0)` or similar. This just gives you *all* public properties of that class which have the attribute. – Jeppe Stig Nielsen Jul 19 '13 at 17:29
  • @Simon: I haven't found any way to reverse the reference, so I'm using your way, and converted the property for the Db Field name into a method that expects you to pass in the actual PropertyInfo or FieldInfo. That works... –  Jul 19 '13 at 17:45
  • @JeppeStigNielsen -> Thanks, but the problem is that I am inside an attribute that could be used on any class/field/property. From inside the attributes code, I want to know what field or property it is attached to. This is for a support dll, and it will have no advanced knowledge of what classes or fields it will be used on. (thanks though) –  Jul 19 '13 at 17:47
  • Okay, so there is an instance constructor `public DbFieldAttribute(string name) { /* your nice code here! */ }`. The _existence_ of this constructor is the reason why it is valid to specify the attribute like `[DbField("User_Id")]`. This is verified at ***compile-time***. Do you assume that "your nice code" (the body of the constructor) is actually run because you apply the constructor? When would it run? At compile-time? It doesn't run until you hit some code (like that in my last comment) which actually "gets" the custom attribute. So in short, I don't think what you want to do is possible. – Jeppe Stig Nielsen Jul 19 '13 at 23:33
  • @JeppeStigNielsen No, I did not expect it to just run. What I was hoping for is that when methods inside an attribute class are called, that they would have a way to return the methodInfo, propertyInfo, etc, that it was attached to. Sort of like an application can tell the path of the executable it started from. That would be especially valuable so you automatically have more information on the data type, the property name, the visibility, the value, etc... –  Aug 27 '13 at 03:29

2 Answers2

0

Unfortunately, to the best of my knowledge, there is no way to accomplish what you are asking for.

But if it is not necessary that you get the PropertyInfo or the FieldInfo object inside your constructor, but instead you would be satisfied with it being passed to a method, then there is a possible solution.

First of all, your DbField class would need to be defined in the following way.

class DbField : Attribute
{
    public DbField(string source) { }

    public void GetInstance(PropertyInfo source)
    {
        Console.WriteLine(source.Name);
    }
}

You would then need to define the following class which would get all the (in this case) properties marked with the DbField attribute, and pass them to the GetInstance(PropertyInfo) method.

class ActivateAttributes
{
    public ActivateAttributes(object source)
    {
        source.GetType()
              .GetProperties()
              .Where(x => x.GetCustomAttributes().OfType<DbField>().Any())
              .ToList()
              .ForEach(x => (x.GetCustomAttributes().OfType<DbField>().First() as DbField).GetInstance(x));
    }
}

The way you would trigger this process is inside an abstract class, which is defined as so.

abstract class AbstractDecoratedClass
{
    public AbstractDecoratedClass()
    {
        new ActivateAttributes(this);
    }
}

Now your target class, which has its properties decorated by DbField attributes, simply needs to derive from this class, so that you won't be bothered by the invocation inside the constructor.

class DecoratedClass : AbstractDecoratedClass
{
    [DbField("User_Id")]
    public int UserId { get; set; }

    [DbField("User_Id2")]
    public int UserId2 { get; set; } 
}

You are now only left with testing the solution as shown here.

class Program
{
    static void Main()
    {
        new DecoratedClass();

        Console.Read();
    }
}
Mario Stopfer
  • 541
  • 3
  • 8
  • This seems a bit more complex than it needs to be. The key that makes this solution work (the same key that helped me solve this) was that something outside needs to pass in the class or the prop/fieldinfo to the attribute. All I did was change the property for FieldName, into a pair of overloaded methods expecting either the propertyinfo or fieldinfo to be passed into it. Then, if the FieldName was never set, it will just return the name from the info. –  Jul 22 '13 at 14:41
  • Both ways solve the problem, just not as elegantly as I was hoping .NET would handle. In most other cases, you can use stack trace information to find out the parent, but in this case, the stack trace resolves back to the ORM instead of the class-Field/Property. -- Thanks. –  Jul 22 '13 at 14:44
  • I wish I could apply Successful answer to both your posted solution and mine, because you did provide a valid solution. I chose mine, because I feel that it is a simpler option to implement/understand. Thanks. –  Jul 22 '13 at 14:56
0

The solution could not be solved directly, as @Mario pointed out, but here is the solution I ended up going with.

The key is to know that the attribute alone has no way of knowing this information, but at the time it is called it is reasonable to expect that the FieldInfo or PropertyInfo was also available.

My original problem was that my ORM code looked to an attribute to determine if a field/property related to a database field. Then, I had instances where the Prop/Field name in the class did not match up with the database for reasons of making it more logical to the Code/Db. In those cases I needed to pass in a field name to use instead of the actual field. I was hoping the attribute could do more of the work, or at least help make it more obvious for any future code that used it.

(I stripped out xml comments and extra code not relavant to this solution)

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class DbFieldAttribute : Attribute
{
    private string fieldName = "";

    public DbFieldAttribute() { }

    public DbFieldAttribute(string fieldName)
    {
        this.fieldName = fieldName;
    }

    public string FieldName(PropertyInfo pi)
    {
        if (this.fieldName != "") return this.fieldName;
        else return pi.Name;
    }

    public string FieldName(FieldInfo fi)
    {
        if (this.fieldName != "") return this.fieldName;
        else return fi.Name;
    }

Now when my ORM code wants the field name, it has to pass in the field or property info related to that field. This means that what is needed, is now intrinsic in the attributes use, instead of needing to be derived in external code.