Reputation: 19742
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
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
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