Кто-нибудь знает быстрый способ получить доступ к пользовательским атрибутам по значению enum?
-
09-06-2019 - |
Вопрос
Вероятно, лучше всего это показать на примере.У меня есть перечисление с атрибутами:
public enum MyEnum {
[CustomInfo("This is a custom attrib")]
None = 0,
[CustomInfo("This is another attrib")]
ValueA,
[CustomInfo("This has an extra flag", AllowSomething = true)]
ValueB,
}
Я хочу получить доступ к этим атрибутам из экземпляра:
public CustomInfoAttribute GetInfo( MyEnum enumInput ) {
Type typeOfEnum = enumInput.GetType(); //this will be typeof( MyEnum )
//here is the problem, GetField takes a string
// the .ToString() on enums is very slow
FieldInfo fi = typeOfEnum.GetField( enumInput.ToString() );
//get the attribute from the field
return fi.GetCustomAttributes( typeof( CustomInfoAttribute ), false ).
FirstOrDefault() //Linq method to get first or null
as CustomInfoAttribute; //use as operator to convert
}
Поскольку при этом используется отражение, я ожидаю некоторой медлительности, но кажется грязным преобразовывать значение enum в строку (которая отражает имя), когда у меня уже есть его экземпляр.
У кого-нибудь есть способ получше?
Решение
Это, наверное, самый простой способ.
Более быстрым способом было бы статически выдавать IL-код, используя Dynamic Method и ILGenerator.Хотя я использовал это только для GetPropertyInfo, но не могу понять, почему вы также не могли создать CustomAttributeInfo.
Например, код для получения средства получения из свойства
public delegate object FastPropertyGetHandler(object target);
private static void EmitBoxIfNeeded(ILGenerator ilGenerator, System.Type type)
{
if (type.IsValueType)
{
ilGenerator.Emit(OpCodes.Box, type);
}
}
public static FastPropertyGetHandler GetPropertyGetter(PropertyInfo propInfo)
{
// generates a dynamic method to generate a FastPropertyGetHandler delegate
DynamicMethod dynamicMethod =
new DynamicMethod(
string.Empty,
typeof (object),
new Type[] { typeof (object) },
propInfo.DeclaringType.Module);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
// loads the object into the stack
ilGenerator.Emit(OpCodes.Ldarg_0);
// calls the getter
ilGenerator.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod(), null);
// creates code for handling the return value
EmitBoxIfNeeded(ilGenerator, propInfo.PropertyType);
// returns the value to the caller
ilGenerator.Emit(OpCodes.Ret);
// converts the DynamicMethod to a FastPropertyGetHandler delegate
// to get the property
FastPropertyGetHandler getter =
(FastPropertyGetHandler)
dynamicMethod.CreateDelegate(typeof(FastPropertyGetHandler));
return getter;
}
Другие советы
Обычно я нахожу отражение довольно быстрым, если вы не вызываете методы динамически.
Поскольку вы просто читаете атрибуты перечисления, ваш подход должен работать просто отлично, без какого-либо реального снижения производительности.
И помните, что вы, как правило, должны стараться делать вещи простыми для понимания.Переусердствовать с этим только ради того, чтобы выиграть несколько мс, возможно, не стоит.