Vra

Vraag gebaseer op MSDN voorbeeld .

Kom ons sê ons het 'n paar C # klasse met HelpAttribute in selfstandige lessenaar toepassing. Is dit moontlik om alle klasse opsom met so 'n kenmerk? Maak dit sin om klasse te erken hierdie manier maak? Persoonlike kenmerk sal gebruik word om 'n lys van moontlike opsies, kies item sal bring om byvoorbeeld van so 'n klas skerm. Aantal klasse / items sal stadig groei, maar hierdie manier waarop ons kan verhoed dat deelinventaris hulle almal elders, ek dink.

Was dit nuttig?

Oplossing

Ja, absoluut. Die gebruik van Refleksie:

static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly) {
    foreach(Type type in assembly.GetTypes()) {
        if (type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0) {
            yield return type;
        }
    }
}

Ander wenke

Wel, jy sal moet opsom deur al die klasse in al die gemeentes wat in die huidige app domein gelaai. Om dit te doen, sal jy die GetAssemblies metode noem op die AppDomain byvoorbeeld vir die huidige app domein.

Van daar, sou jy bel GetExportedTypes (as jy net wil openbare tipes) of GetTypes op elke Assembly om die tipes wat vervat is in die vergadering te kry .

Dan sal jy roep die GetCustomAttributes metode op elke Type byvoorbeeld verby die tipe van die kenmerk wat jy wil om uit te vind .

Jy kan LINQ gebruik om hierdie te vereenvoudig vir jou:

var typesWithMyAttribute =
    from a in AppDomain.CurrentDomain.GetAssemblies()
    from t in a.GetTypes()
    let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
    where attributes != null && attributes.Length > 0
    select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };

Die bogenoemde navraag sal jy elke tipe met jou kenmerk aangewend om dit, saam met die geval van die kenmerk (e) aan hom opgedra.

Let daarop dat as jy 'n groot aantal gemeentes gelaai in jou aansoek domein, kan die operasie duur wees. Jy kan Parallel LINQ gebruik om die tyd van die operasie te verminder, soos so :

var typesWithMyAttribute =
    // Note the AsParallel here, this will parallelize everything after.
    from a in AppDomain.CurrentDomain.GetAssemblies().AsParallel()
    from t in a.GetTypes()
    let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
    where attributes != null && attributes.Length > 0
    select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };

Filter dit op 'n spesifieke Assembly is eenvoudig:

Assembly assembly = ...;

var typesWithMyAttribute =
    from t in assembly.GetTypes()
    let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
    where attributes != null && attributes.Length > 0
    select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };

En as die vergadering het 'n groot aantal tipes in dit, dan kan jy Parallel LINQ gebruik weer:

Assembly assembly = ...;

var typesWithMyAttribute =
    // Partition on the type list initially.
    from t in assembly.GetTypes().AsParallel()
    let attributes = t.GetCustomAttributes(typeof(HelpAttribute), true)
    where attributes != null && attributes.Length > 0
    select new { Type = t, Attributes = attributes.Cast<HelpAttribute>() };

Ander antwoorde verwys GetCustomAttributes . Die toevoeging van hierdie een as 'n voorbeeld van die gebruik van IsDefined

Assembly assembly = ...
var typesWithHelpAttribute = 
        from type in assembly.GetTypes()
        where type.IsDefined(typeof(HelpAttribute), false)
        select type;

Soos reeds gemeld, besinning is die pad om te gaan. As jy gaan om dit gereeld te bel, ek hoogs stel voor kas die resultate, as weerspieëling, veral deelinventaris deur elke klas, kan nogal stadig wees.

Dit is 'n uittreksel van my kode wat deur al die soorte in alle gelaai gemeentes loop:

// this is making the assumption that all assemblies we need are already loaded.
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 
{
    foreach (Type type in assembly.GetTypes())
    {
        var attribs = type.GetCustomAttributes(typeof(MyCustomAttribute), false);
        if (attribs != null && attribs.Length > 0)
        {
            // add to a cache.
        }
    }
}

Dit is 'n verbetering van prestasie op die top van die aanvaarde oplossing. Iterating al alle klasse kan stadig wees, want daar is so baie. Soms kan jy filter 'n hele gemeente sonder om na enige van sy soort.

Byvoorbeeld, as jy op soek is vir 'n spesifieke eienskap wat jy jouself verklaar, het jy nie verwag dat enige van die stelsel DLLs om enige tipes met daardie eienskap bevat. Die Assembly.GlobalAssemblyCache eiendom is 'n vinnige manier om te kyk vir stelsel DLLs. Toe ek hierdie probeer op 'n werklike program het ek gevind ek kon 30101 tipes slaan en ek het net na 1983 tipes te gaan.

Nog 'n manier om filter is om Assembly.ReferencedAssemblies gebruik. Vermoedelik as jy klasse met 'n spesifieke kenmerk wil, en dat kenmerk word gedefinieer in 'n spesifieke gemeente, dan kan jy net omgee vir daardie gemeente en ander gemeentes wat daarna verwys. In my toetse gehelp hierdie effens meer as die beheer van die eiendom GlobalAssemblyCache.

Ek gekombineer beide van hierdie en het dit selfs vinniger. onder die kode sluit beide filters.

        string definedIn = typeof(XmlDecoderAttribute).Assembly.GetName().Name;
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            // Note that we have to call GetName().Name.  Just GetName() will not work.  The following
            // if statement never ran when I tried to compare the results of GetName().
            if ((!assembly.GlobalAssemblyCache) && ((assembly.GetName().Name == definedIn) || assembly.GetReferencedAssemblies().Any(a => a.Name == definedIn)))
                foreach (Type type in assembly.GetTypes())
                    if (type.GetCustomAttributes(typeof(XmlDecoderAttribute), true).Length > 0)

In die geval van die draagbare NET beperkings die volgende kode moet werk:

    public static IEnumerable<TypeInfo> GetAtributedTypes( Assembly[] assemblies, 
                                                           Type attributeType )
    {
        var typesAttributed =
            from assembly in assemblies
            from type in assembly.DefinedTypes
            where type.IsDefined(attributeType, false)
            select type;
        return typesAttributed;
    }

of vir 'n groot aantal gemeentes met behulp van lus-staat gebaseer yield return:

    public static IEnumerable<TypeInfo> GetAtributedTypes( Assembly[] assemblies, 
                                                           Type attributeType )
    {
        foreach (var assembly in assemblies)
        {
            foreach (var typeInfo in assembly.DefinedTypes)
            {
                if (typeInfo.IsDefined(attributeType, false))
                {
                    yield return typeInfo;
                }
            }
        }
    }

Ons kan verbeter op antwoord Andrew's en sit die hele ding in 'n LINQ navraag.

    public static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly)
    {
        return assembly.GetTypes().Where(type => type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0);
    }
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top