سؤال

والسؤال استنادا <لأ href = "https://web.archive.org/web/20170228051218/https://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx" يختلط = "noreferrer"> MSDN سبيل المثال .

ودعونا نقول أن لدينا بعض الطبقات C # مع HelpAttribute في تطبيقات سطح المكتب المستقل. هل من الممكن أن تعداد جميع الطبقات مع هذه السمة؟ هل يعقل أن تعترف الطبقات بهذه الطريقة؟ وسوف تستخدم سمة مخصصة لقائمة خيارات القائمة ممكنة، واختيار البند جلب لفحص مثيل هذه الفئة. وعدد الفصول / البنود تنمو ببطء، ولكن بهذه الطريقة يمكننا تجنب تعداد كل منها في أي مكان آخر، على ما أعتقد.

هل كانت مفيدة؟

المحلول

نعم، بالتأكيد. عن طريق التأمل:

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

نصائح أخرى

حسنا، أنت لن يكون تعداد من خلال كافة الفئات في كل التجميعات التي يتم تحميلها في مجال التطبيق الحالي. للقيام بذلك، وكنت استدعاء GetAssemblies طريقة على و AppDomain المثال للمجال التطبيق الحالي.

ومن هناك، هل ندعو GetExportedTypes (إذا كنت تريد فقط أنواع العامة) أو GetTypes Assembly للحصول على الأنواع التي ترد في البرلمان .

وبعد ذلك، كنت استدعاء GetCustomAttributes طريقة على كل Type سبيل المثال، ويمر نوع السمة التي ترغب في العثور .

ويمكنك استخدام LINQ لتبسيط هذا بالنسبة لك:

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

والاستعلام أعلاه سوف تحصل على كل نوع مع السمة الخاصة بك المطبق عليه، جنبا إلى جنب مع مثيل السمة (ق) المخصصة لذلك.

لاحظ أنه إذا كان لديك عدد كبير من الجمعيات تحميل في مجال التطبيق الخاص بك، هذه العملية يمكن أن تكون مكلفة. يمكنك استخدام بالتوازي مع LINQ لتقليل وقت العملية، مثل ذلك :

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

وتصفية ذلك على Assembly محددة بسيطة:

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

وإذا كان التجمع لديها عدد كبير من الأنواع في ذلك، ثم يمكنك استخدام الموازي LINQ مرة أخرى:

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

وأجوبة أخرى مرجع GetCustomAttributes . واضاف هذا واحد كمثال على استخدام IsDefined

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

وكما ذكر سابقا، والتفكير هو الطريق للذهاب. إذا كنت تسير على هذه الكلمة في كثير من الأحيان، وأنا اقترح عالية التخزين المؤقت النتائج، والتفكير، وخاصة من خلال تعداد كل فئة، يمكن أن تكون بطيئة للغاية.

وهذا هو مقتطف من قانون بلدي الذي يمر عبر كل أنواع في جميع الجمعيات تحميل:

// 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.
        }
    }
}

وهذا هو تحسين الأداء على أعلى حل مقبول. يمكن بالتكرار على الرغم من جميع الطبقات تكون بطيئة لأن هناك الكثير من ذلك. في بعض الأحيان يمكنك تصفية جمعية بأكمله دون النظر إلى أي من أنواعه.

وعلى سبيل المثال إذا كنت تبحث عن السمة التي أعلن نفسك، لا تتوقع أي من دلس نظام لاحتواء أي أنواع مع تلك السمة. الخاصية Assembly.GlobalAssemblyCache هو وسيلة سريعة للتحقق من دلس النظام. عندما حاولت ذلك على برنامج حقيقي وجدت أنني قد تخطي 30101 أنواع وليس لدي سوى للتحقق 1،983 أنواع.

وهناك طريقة أخرى لمرشح لاستخدام Assembly.ReferencedAssemblies. يفترض إذا كنت تريد الطبقات ذات سمة محددة، ويتم تحديد تلك السمة في تجميع محدد، فإنك لا يهتمون إلا أن الجمعية والجمعيات الأخرى التي تشير إلى ذلك. في بلدي التجارب هذا ساعد أكثر قليلا من التحقق من الملكية GlobalAssemblyCache.

وأنا جنبا إلى جنب كل من هذه وحصلت عليه حتى أسرع. ويتضمن رمز أدناه كل من المرشحات.

        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)

في حالة المحمولة. NET القيود و، التعليمة البرمجية التالية يجب أن تعمل:

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

وأو لعدد كبير من التجمعات باستخدام 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;
                }
            }
        }
    }

ويمكننا تحسين الجواب أندرو وتحويل كل شيء إلى استعلام LINQ واحد.

    public static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly)
    {
        return assembly.GetTypes().Where(type => type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0);
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top