Значение по умолчанию для атрибута = Имя поля с атрибутом - PullRequest
2 голосов
/ 04 марта 2011

У меня есть атрибут, конструктор которого принимает две строки.Я хотел бы сделать вторую строку необязательным параметром.Если пользователь атрибута не предоставляет значение для второго параметра, его значение должно быть равно названию поля, содержащего атрибут.Как мне этого добиться?


Вот мой код:

[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);
    }
}

Ответы [ 2 ]

3 голосов
/ 04 марта 2011

Я не верю, что ты можешь, я боюсь.Насколько мне известно, нет способа перейти от атрибута к члену (или какому-либо другому), к которому он применяется.

2 голосов
/ 04 марта 2011

Хотя вы не можете этого сделать, код, который обрабатывает атрибут, может проверить вторую строку и, если она пуста, получить имя поля, к которому применяется этот атрибут.

Простой решение для вашего примера:

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;
  }

...
...