কাস্টম শ্রেণীর বৈশিষ্ট্য সহ সমস্ত শ্রেণি কিভাবে গণনা করা যায়?


151

উপর ভিত্তি করে প্রশ্ন দুটিই MSDN উদাহরণ

ধরা যাক আমাদের একক ডেস্কটপ অ্যাপ্লিকেশনটিতে হেল্পএট্রিবিউট সহ কয়েকটি সি # ক্লাস রয়েছে। এই জাতীয় গুণাবলী সহ সমস্ত শ্রেণীর গণনা করা কি সম্ভব? ক্লাসগুলি এভাবে চিনতে কী বোঝায়? সম্ভাব্য মেনু বিকল্পগুলির তালিকা করতে কাস্টম অ্যাট্রিবিউট ব্যবহার করা হবে, আইটেম নির্বাচন করা এ জাতীয় শ্রেণীর স্ক্রিন উদাহরণ এনে দেবে। ক্লাস / আইটেমের সংখ্যা ধীরে ধীরে বৃদ্ধি পাবে, তবে এইভাবে আমরা অন্য কোথাও এগুলি গণনা এড়াতে পারি, আমি মনে করি।

উত্তর:


205

অবশ্যই হ্যাঁ. প্রতিবিম্ব ব্যবহার:

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

7
সম্মত, তবে এক্ষেত্রে আমরা এটি ক্যাস্পারওনের সমাধান অনুসারে ঘোষণামূলকভাবে করতে পারি। ফলনটি ব্যবহার করতে সক্ষম হওয়ায় এটি খুব সুন্দর, এটির দরকারও নেই :)
জন স্কিটি

9
আমি লিনকিউ পছন্দ করি। আসলে ভালোবাসি। তবে এটি .NET 3.5 এর উপর নির্ভরতা নেয়, যা ফলন ফেরত দেয় না। এছাড়াও, লিনকিউ অবশেষে ফলন ফেরতের হিসাবে একই জিনিসটিতে ভেঙে যায়। তাহলে আপনি কি অর্জন করেছেন? একটি নির্দিষ্ট সি # বাক্য গঠন, এটি একটি পছন্দ।
অ্যান্ড্রু অরনট

1
@ অ্যান্ড্রুআরনট সবচেয়ে কম এবং সংক্ষিপ্ত কোডের লাইনগুলি কার্য সম্পাদনের জন্য অপ্রাসঙ্গিক, এগুলি কেবল পঠনযোগ্যতা এবং রক্ষণাবেক্ষণের ক্ষেত্রে সম্ভাব্য অবদানকারী। আমি এই বিবৃতিটিকে চ্যালেঞ্জ জানাই যে তারা সবচেয়ে কম অবজেক্ট বরাদ্দ করেছে এবং কার্য সম্পাদন দ্রুত হবে (বিশেষত অভিজ্ঞতামূলক প্রমাণ ছাড়াই); আপনি মূলত Selectএক্সটেনশন পদ্ধতিটি লিখেছেন এবং সংকলক একটি রাজ্য মেশিন তৈরি করবে ঠিক তেমনভাবে যদি আপনি Selectআপনার ব্যবহারের কারণে কল করেন yield return। অবশেষে, কোন কার্য সম্পাদনে লাভ যে পারে অধিকাংশ ক্ষেত্রে এ প্রাপ্ত করা মাইক্রো-অপ্টিমাইজেশন হও।
CasperOne

1
বেশ ডান, @ ক্যাস্পার ওনে। একটি খুব সামান্য পার্থক্য, বিশেষত প্রতিফলনের ওজনের সাথে তুলনা করে। সম্ভবত কখনও একটি নিখুঁত ট্রেস আসতে হবে না।
অ্যান্ড্রু আরনট

1
অবশ্যই রিশার্পার বলেছে যে "ফোরচ লুপটি একটি লিনকিউ এক্সপ্রেশনতে রূপান্তরিত হতে পারে" যা দেখতে এটির মতো: এসেম্বলি.গেটটাইপস ()। যেখানে (টাইপ => টাইপ।গেটকাস্টমঅ্যাট্রিবিউটস (টাইপফ (হেল্পঅ্যাট্রিবিউট), সত্য)। দৈর্ঘ্য> 0);
ডেভিড ব্যারোস

107

ঠিক আছে, আপনাকে বর্তমান অ্যাপ্লিকেশন ডোমেনে লোড করা সমস্ত অ্যাসেমব্লির সমস্ত শ্রেণীর মধ্য দিয়ে গণনা করতে হবে। যে কাজের জন্য, আপনি কল করবে GetAssembliesপদ্ধতি উপর AppDomainবর্তমান অ্যাপ্লিকেশান ডোমেনের জন্য উদাহরণস্বরূপ।

সেখান থেকে, আপনি সমাবেশ করতে GetExportedTypesচান (যদি আপনি কেবল সর্বজনীন প্রকার চান) বা GetTypesপ্রত্যেকটিতে Assemblyসমাবেশগুলিতে থাকা ধরণেরগুলি পেতে।

তারপরে, আপনি প্রতিটি উদাহরণে GetCustomAttributesএক্সটেনশন পদ্ধতিতে কল করবেন, আপনি Typeযে বৈশিষ্ট্যের সন্ধান করতে চান তার ধরণটি পাস করে।

এটি আপনার জন্য সহজ করার জন্য আপনি লিনকিউ ব্যবহার করতে পারেন:

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

উপরোক্ত ক্যোয়ারী আপনাকে এতে নির্দিষ্ট করা অ্যাট্রিবিউট (গুলি) এর উদাহরণ সহ আপনার প্রতিটি প্রকারের সাথে এটি প্রয়োগ করা হবে।

মনে রাখবেন যে আপনার অ্যাপ্লিকেশন ডোমেনে প্রচুর সংখ্যক সমাবেশগুলি লোড করা থাকলে সেই অপারেশন ব্যয়বহুল হতে পারে। অপারেশনের সময় কমাতে আপনি সমান্তরাল লাইনকিউ ব্যবহার করতে পারেন , যেমন:

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

এবং যদি সমাবেশে এটির একটি বিশাল সংখ্যক প্রকার থাকে তবে আপনি আবার সমান্তরাল লিনকিউ ব্যবহার করতে পারেন:

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

1
সমস্ত লোড করা অ্যাসেমব্লিতে সমস্ত ধরণের গণনা করা খুব ধীর হবে এবং আপনাকে বেশি লাভ করবে না। এটিও একটি সম্ভাব্য সুরক্ষা ঝুঁকি। আপনি সম্ভবত আন্দাজ করতে পারেন যে কোন অ্যাসেমব্লিতে আপনার আগ্রহী সেগুলি রয়েছে Just কেবলমাত্র সেগুলির মধ্যে প্রকারগুলি গণনা করুন।
অ্যান্ড্রু অরনট

@ অ্যান্ড্রু আরনট: সঠিক, তবে এটিই যা চেয়েছিল। নির্দিষ্ট সমাবেশে ক্যোয়ারী ছাঁটাই করা যথেষ্ট সহজ। প্রকার এবং গুণাবলীর মধ্যে আপনাকে ম্যাপিং দেওয়ার অতিরিক্ত সুবিধাও রয়েছে।
ক্যাস্পার ওয়ান


@ ক্রিসমোসচিনি হ্যাঁ, আপনি পারেন তবে আপনি সর্বদা বর্তমান সমাবেশটি স্ক্যান করতে চান না। এটি খোলা রাখা ভাল।
ক্যাস্পারওন

আমি এটি বহুবার করেছি এবং এটিকে দক্ষ করে তোলার অনেকগুলি উপায় নেই। আপনি মাইক্রোসফ্ট অ্যাসেমব্লিগুলি এড়িয়ে যেতে পারেন (তারা একই কী দিয়ে স্বাক্ষরিত হয়েছে, তাই তারা એસেম্বলনেম ব্যবহার করা এড়াতে খুব সহজ a এর মধ্যে অন্যরা লোড হওয়ার ক্ষেত্রে আপনি যে সম্মেলনগুলি পরীক্ষা করেছেন সেগুলির নাম) the

34

অন্যান্য উত্তর রেফারেন্স গেটকাস্টমঅ্যাট্রিবিউটসইসডাফাইনযুক্ত ব্যবহারের উদাহরণ হিসাবে এটি যুক্ত করা

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

3
আমি এটি বিশ্বাস করি এটি সঠিক সমাধান যা কাঠামোর উদ্দেশ্যে পদ্ধতি ব্যবহার করে method
আলেক্সি ওমেলচেনকো

11

যেমন ইতিমধ্যে বলা হয়েছে, প্রতিবিম্ব হ'ল উপায়। আপনি যদি এটি ঘন ঘন কল করতে চলেছেন তবে আমি ফলাফলগুলি ক্যাশে করার জন্য অত্যন্ত পরামর্শ দিচ্ছি, প্রতিচ্ছবি হিসাবে, বিশেষত প্রতিটি শ্রেণীর মাধ্যমে গণনা করা বেশ ধীর হতে পারে।

এটি আমার কোডের একটি স্নিপেট যা সমস্ত বোঝা সমাবেশগুলিতে সমস্ত ধরণের মাধ্যমে চলে:

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

9

এটি গৃহীত সমাধানের শীর্ষে পারফরম্যান্স বর্ধন। সমস্ত শ্রেণি যদিও ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে সেগুলিতে কাটা যায়। কখনও কখনও আপনি কোনও প্রকারের দিকে না তাকিয়ে একটি সম্পূর্ণ সমাবেশ ফিল্টার করতে পারেন।

উদাহরণস্বরূপ, আপনি যদি নিজেকে এমন একটি গুণাবলীর সন্ধান করছেন যা আপনি নিজেকে ঘোষণা করেছেন, আপনি সিস্টেম ডিএলএলগুলির কোনওরূপে সেই বৈশিষ্ট্যের সাথে কোনও ধরণের থাকবে বলে আশা করবেন না। অ্যাসেম্বলি.গ্লোবালঅ্যাস্প্যাশনে ক্যাশে সম্পত্তি সিস্টেম ডিএলএলগুলির জন্য চেক করার একটি দ্রুত উপায়। আমি যখন এটি একটি বাস্তব প্রোগ্রামে চেষ্টা করেছি তখন আমি দেখতে পেলাম যে আমি 30,101 প্রকারগুলি এড়িয়ে যেতে পারি এবং আমাকে কেবল 1,983 প্রকারগুলি পরীক্ষা করতে হবে।

ফিল্টার করার আরেকটি উপায় হ'ল এসেম্বলি.ইফেরেন্সড এসেম্বলিস ব্যবহার করা। সম্ভবত আপনি যদি একটি নির্দিষ্ট অ্যাট্রিবিউটের সাথে ক্লাস চান, এবং সেই অ্যাট্রিবিউটটি একটি নির্দিষ্ট সমাবেশে সংজ্ঞায়িত করা হয় তবে আপনি কেবল সেই সমাবেশ এবং অন্যান্য অ্যাসেমব্লির বিষয়ে যত্নশীল যা এটি উল্লেখ করে। আমার পরীক্ষাগুলিতে এটি গ্লোবালএস্প্যাশনের ক্যাশে সম্পত্তি যাচাই করার চেয়ে কিছুটা বেশি সহায়তা করেছে।

আমি এই উভয়কে একত্রিত করেছি এবং এটি আরও দ্রুত পেয়েছি। নীচের কোডটিতে উভয় ফিল্টার অন্তর্ভুক্ত রয়েছে।

        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)

4

ক্ষেত্রে পোর্টেবল .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;
                }
            }
        }
    }

0

আমরা অ্যান্ড্রুয়ের উত্তরে উন্নতি করতে এবং পুরো জিনিসটিকে একটি লিনকিউ কোয়েরিতে রূপান্তর করতে পারি।

    public static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly)
    {
        return assembly.GetTypes().Where(type => type.GetCustomAttributes(typeof(HelpAttribute), true).Length > 0);
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.