简体   繁体   中英

Passing Attributes of a Auto-Implemented Property to its field

I have the following Problem: I would like to add an attribute to an auto-implemented property prop of a class Foo in the first step. In a second step I'm iterating over all fields of Foo and I copy values to these fields (values of fields of auto-implemented Properties are also found and copied). In this part I need access to the information of the Attribute.

class FieldSetter
{
    // This Method is called from outside and should work for any class
    private void SetFieldValues(object unknownObject)
    {
        foreach (var field in
                unknownObject.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |
                                       BindingFlags.Static).Where((field) => !field.IsLiteral))
        {
            if (!EvalAttribute(Attribute.GetCustomAttributes(field))) // the Attribute should be accessed here
            {
                // Do something if no special Information is set
                field.SetValue(a, "default Value");
            }

            else
            {
                // Do special things
                field.SetValue(a, "special Value");
            }
        }

    }


    internal static bool EvalAttribute(Attribute[] attributes)
    {

        foreach (System.Attribute attr in attributes)
        {
            var myAttr = attr as MyAttribute;
            if (myAttr != null)
            {
                if (myAttr.SomeAttributeValues == "Specific Attribute Value")
                {
                    return true;
                }
            }
        }
        return false;
    }
}

// This class is a example for how a given Object can look like
class Foo
{
    [MyAttribute("Example Information")] // This Attribute won't be accessed via prop-Field
    int prop { get; set; }

    [MyAttribute("Another Example Information")] // This Attribute won't be accessed via prop-Field
    int field;

    //... lots of other fields and properties
}


[System.AttributeUsage(System.AttributeTargets.All)]
class MyAttribute : Attribute
{
    public MyAttribute(string someInformation)
    {
        SomeAttributeValues = someInformation;
    }

    public string SomeAttributeValues;
}

You can't do this. If you need to have the attribute on the field, you need to declare the field yourself and not use auto-properties. Alternately, you can reflect over the properties which will have the attribute when you look for them.

If you can guarantee that the properties you're interested in will always be auto-implemented, and you have some idea of what compiler will be used to compile the types you're interested in, you could leverage the fact that the backing fields for auto-generated properties follow a specific naming convention. For example, the code you've provided ends up with a field name like this:

<prop>k__BackingField

This is a distinctive name, which cannot be produced directly by C# code, so if you run into a field with a name like this you could parse out the property name from between the angle brackets, and use GetProperty() on that name.

However, this is a hacky solution because:

  1. The name used for backing fields is an implementation detail, which could theoretically change in future versions of .NET, or for alternative compilers like Mono.
  2. There's nothing to ensure that the fields you find will always be tied to auto-properties. What would your expectations be if you ran into this?

     class Foo { int field; [MyAttribute("Example Information")] int prop { get{return field;} set {return field;} } //... lots of other fields and properties } 

I'd strongly suggest that you spend more time analyzing what your real business need and constraints are, and see if there's not another, more robust way to approach this problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM