isekaijin
isekaijin

Reputation: 19742

Attribute's default value = Name of the field possessing the attribute

I have an attribute whose constructor takes two strings. I would like to make the second string an optional parameter. If the user of the attribute does not supply a value for the second parameter, its value should be equal to the name of the field possesing the attribute. How could I achieve that?


Here is my code:

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class WSFieldAttribute : Attribute
{
    private string tableField;
    private string xmlField;

    public WSFieldAttribute(string tableField, string xmlField)
    {
        this.tableField = tableField;
        this.xmlField   = xmlField;
    }

    public object this[DataRow row]
    {
        get { return row[this.tableField]; }
    }

    public object this[XmlWriter writer]
    {
        set
        {
            string toString;

            if (value.GetType() == typeof(string))
                toString = (string)value;
            else if (value.GetType() == typeof(DateTime))
                toString = Utilities.FormatDate((DateTime)value);
            else if (value.GetType() == typeof(DateTime?))
                toString = Utilities.FormatDate((DateTime?)value);
            else
                toString = value.ToString();

            writer.WriteAttributeString(this.xmlField, toString);
        }
    }
}

public class FieldDefinition
{
    private FieldInfo        fieldInfo;
    private WSFieldAttribute wsField;

    public FieldDefinition(FieldInfo fieldInfo)
    {
        object[] customAttributes = fieldInfo.GetCustomAttributes(typeof(WSFieldAttribute), false);

        if (customAttributes.Length != 1)
            throw new InvalidProgramException();

        this.fieldInfo = fieldInfo;
        this.wsField = (WSFieldAttribute)customAttributes[0];
    }

    public object this[DataRow row]
    {
        get { return wsField[row]; }
    }

    public string this[XmlWriter writer]
    {
        set { wsField[writer] = value; }
    }

    public void Read(object element, DataRow row)
    {
        fieldInfo.SetValue(element, this.wsField[row]);
    }

    public void Write(object element, XmlWriter writer)
    {
        this.wsField[writer] = fieldInfo.GetValue(element);
    }
}

public class Row<T> : IXmlSerializable where T : class, new()
{
    private static Type type;
    private static LinkedList<FieldDefinition> fieldDefinitions;

    static Row()
    {
        type = typeof(T);

        FieldInfo[] fieldInfos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

        foreach (FieldInfo fieldInfo in fieldInfos)
            fieldDefinitions.AddLast(new FieldDefinition(fieldInfo));
    }

    private T element;

    public Row(DataRow row)
    {
        this.element = new T();

        foreach (FieldDefinition fieldDefinition in fieldDefinitions)
            fieldDefinition.Read(element, row);
    }

    XmlSchema IXmlSerializable.GetSchema() { return null; }

    void IXmlSerializable.ReadXml(XmlReader reader) { throw new NotImplementedException(); }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        foreach (FieldDefinition fieldDefinition in fieldDefinitions)
            fieldDefinition.Write(element, writer);
    }
}

Upvotes: 2

Views: 878

Answers (2)

Jord&#227;o
Jord&#227;o

Reputation: 56457

Although you can't do that, the code that processes the attribute can check the second string, and, if it's null, get the field name that this attribute is applied to.

Simple solution for your example:

public class WSField : Attribute {
  // ...
  internal string xmlField;
  public WSField(string tableField, string xmlField = null) {

...

public class FieldDefinition {
  public FieldDefinition(FieldInfo fieldInfo) {
    // ...
    if (this.wsField.xmlField == null) this.wsField.xmlField = fieldInfo.Name;
  }

...

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1499730

I don't believe you can, I'm afraid. As far as I'm aware, there's no way of going from an attribute instead to the member (or whatever) it's applied to.

Upvotes: 3

Related Questions