获得AppDomain中所有类型标记特定属性的最有效方法是什么?

时间:2011-10-07 20:55:56

标签: c# reflection

如果我这样做,我会在我的程序中枚举所有类型:

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 个答案:

答案 0 :(得分:8)

好吧,使用更多LINQ并使用IsDefined至少使代码更好(并获取类型,而不是属性......)

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

现在,您询问效率 - 这需要多长时间?它需要多长时间可接受?你经常打电话吗? (这看起来很奇怪。)

另请注意,它仅包含已加载的程序集 - 可能存在尚未加载的引用程序集;那个没被拿起的重要吗?

答案 1 :(得分:7)

在这里通常使用效率最高的是Attribute.IsDefined(...),尽管在[Serializable] 的特定情况下type.IsSerializable是更快(在这种情况下它实际上并不存储为属性 - 它在编译器中有特殊处理,映射到CLI标志)。

答案 2 :(得分:2)

不,不是。并注意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();
}

答案 3 :(得分:1)

您可以这样做:

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