Самый эффективный способ пометить все типы в AppDomain определенным атрибутом? - PullRequest
3 голосов
/ 08 октября 2011

Если я сделаю это, я перечислю все типы в моей программе:

List<SerializableAttribute> attributes=new List<SerializableAttribute>() ;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    foreach (Type type in assembly.GetTypes())
    {
        attributes.AddRange(
                            type.GetCustomAttributes(false)
                            .OfType<SerializableAttribute>()
                            .ToList());
    }
}

Являются ли метаданные, поставляемые с .NET dll, проиндексированными, чтобы я мог сделать что-то вроде:

List<SerializableAttribute> attributes = typeof(SerializableAttribute)
                                         .GetClassesIAmDefinedOn();

Есть ли другой вариант, который я не рассматриваю?

(SerializableAttribute - просто пример)

Ответы [ 4 ]

8 голосов
/ 08 октября 2011

Что ж, использование LINQ more и использование IsDefined как минимум делает код приятнее (и выбирает типы, а не атрибуты ...)

var types = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
             from type in assembly.GetTypes()
             where Attribute.IsDefined(type, typeof(SerializableAttribute))
             select type).ToList();

Теперь вы спросили о эффективности - сколько времени это займет? Сколько времени это займет приемлемо ? Вы звоните это часто? (Это может показаться странным.)

Также обратите внимание, что он включает только сборки, которые уже были загружены - это может быть ссылка на сборку, которая еще не была загружена; это имеет значение, что это не поднято?

7 голосов
/ 08 октября 2011

Наиболее эффективная вещь для использования здесь обычно - это Attribute.IsDefined(...), хотя в конкретном случае [Serializable], type.IsSerializable быстрее (фактически не сохраняетсякак атрибут в этом одном случае - он имеет специальную обработку в компиляторе, сопоставленную с флагом CLI).

2 голосов
/ 08 октября 2011

Нет, это не так.И остерегайтесь GetCustomAttributes.Это очень дорого и эффективно не кешируется.AppDomain.Current.Domain.GetAssemblies также очень дорогой.

Для таких вещей я держу кеш в Словаре

var cache = new Dictionary<Assembly,Attribute[]>();

foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    var attributes = new List<SerializableAttribute>();
    foreach (Type type in assembly.GetTypes())
    {
        attributes.AddRange(
                            type.GetCustomAttributes(false)
                            .OfType<SerializableAttribute>()
                            .ToList());
    }
    cache[assembly] = attributes.ToArray();
}
1 голос
/ 08 октября 2011

Вы можете сделать либо:

var assem = // get assembly:
var types = assem.GetTypes().Where(t => t.IsDefined(typeof(SerializableAttribute)));

Или, если вы хотите сделать это наоборот:

public static IEnumerable<Type> WhereDefinedOn(this Type type, IEnumerable<Type> types)
{
    if (!typeof(Attribute).IsAssignableFrom(type))
        throw new InvalidOperationException("Only attribute types are supported.");

    return types.Where(t => t.IsDefined(type));
}

Который вы можете использовать как:

var allTypes = assem.GetTypes();
var filteredTypes = typeof(SerializableAttribute).WhereDefinedOn(allTypes);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...