Пользовательские атрибуты членов класса
-
08-07-2019 - |
Вопрос
Я использую настраиваемый атрибут, чтобы определить, как члены класса сопоставляются со свойствами для публикации в виде сообщения формы (Платежный шлюз).У меня пользовательский атрибут работает нормально, и я могу получить атрибут по «имени», но хотел бы получить атрибут по самому члену.
Например:
getFieldName("name");
против
getFieldName(obj.Name);
План состоит в том, чтобы написать метод для сериализации класса с членами в публикуемую строку.
Вот тестовый код, который у меня есть на данный момент, где ret — это строка, а PropertyMapping — это пользовательский атрибут:
foreach (MemberInfo i in (typeof(CustomClass)).GetMember("Name"))
{
foreach (object at in i.GetCustomAttributes(true))
{
PropertyMapping map = at as PropertyMapping;
if (map != null)
{
ret += map.FieldName;
}
}
}
Заранее спасибо!
Решение
На самом деле вы не сможете этого сделать, если только вы не используете C # 3.0, и в этом случае вам придется полагаться на LINQ (хм, деревья выражений).
Что вы делаете, так это создаете фиктивный метод для лямбда-выражения, который позволяет компилятору генерировать дерево выражений (компилятор выполняет проверку типов).Затем вы копаетесь в этом дереве, чтобы получить член.Вот так:
static FieldInfo GetField<TType, TMemberType>(
Expression<Func<TType, TMemberType>> accessor)
{
var member = accessor.Body as MemberExpression;
if (member != null)
{
return member.Member as FieldInfo;
}
return null; // or throw exception...
}
Учитывая следующий класс:
class MyClass
{
public int a;
}
Вы можете получить метаданные следующим образом:
// get FieldInfo of member 'a' in class 'MyClass'
var f = GetField((MyClass c) => c.a);
Ссылаясь на это поле, вы можете найти любой атрибут обычным способом.то естьотражение.
static TAttribute GetAttribute<TAttribute>(
this MemberInfo member ) where TAttribute: Attribute
{
return member.GetCustomAttributes( typeof( TAttribute ), false )
.Cast<TAttribute>().FirstOrDefault<TAttribute>();
}
Теперь вы можете откопать атрибут любого поля по чему-то, что по большому счету проверяется компилятором.Он также работает с рефакторингом: если вы переименуете 'a', Visual Studio это уловит.
var attr = GetField((MyClass c) => c.a).GetAttribute<DisplayNameAttribute>();
Console.WriteLine(attr.DisplayName);
В этом коде нет ни одной буквальной строки.
Другие советы
Половину можно сделать немного проще:
foreach (PropertyMapping attrib in
Attribute.GetCustomAttributes(i, typeof(PropertyMapping)))
{
ret += map.FieldName; // whatever you want this to do...
}
кстати;вам следует выработать привычку заканчивать атрибуты словом Attribute
.Даже если это приведет к дублированию (см. [XmlAttributeAttribute]
).
Однако - повторная сериализация;это не всегда тривиально.Обманчивый объем кода попадает в платформы сериализации, такие как Json.NET и т. д.Обычным подходом может быть приобретение преобразователя типов, но во многих отношениях это проще сделать с помощью PropertyDescriptor
:
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
{
Console.WriteLine("{0}={1}",
prop.Name, prop.Converter.ConvertToInvariantString(
prop.GetValue(obj)));
}