Most efficient way to get all types in AppDomain marked with a specific attribute?

五迷三道 提交于 2020-01-04 01:19:21

问题


If I do this, I enumerate over all types in my program:

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

Is metadata that comes with a .NET dll indexed to allow me to do something like:

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

Is there another option that I'm not considering?

(SerializableAttribute is just an example)


回答1:


The most efficient thing to use here generally is Attribute.IsDefined(...), although in the specific case of [Serializable], type.IsSerializable is faster (it isn't actually stored as an attribute in this one case - it has special handling in the compiler, mapping to a CLI flag).




回答2:


Well, using LINQ more and using IsDefined as least makes the code nicer (and fetches the types, not the attributes...)

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

Now, you asked about efficiency - how long does this take? How long is it acceptable for it to take? Are you calling this often? (That would seem odd.)

Also note that it only includes the assemblies which have already been loaded - there could be a referenced assembly which hasn't been loaded yet; does it matter that that isn't picked up?




回答3:


No, it is not. And beware GetCustomAttributes. It's very expensive and not cached effectively. AppDomain.Current.Domain.GetAssemblies is also very expensive.

To do things like this, I keep a cache in a Dictionary

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



回答4:


You could do either:

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

Or, if you want to do it the other way round:

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

Which you can use as:

var allTypes = assem.GetTypes();
var filteredTypes = typeof(SerializableAttribute).WhereDefinedOn(allTypes);


来源:https://stackoverflow.com/questions/7692781/most-efficient-way-to-get-all-types-in-appdomain-marked-with-a-specific-attribut

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!