ইন্টারফেস উত্তরাধিকারের শ্রেণিবিন্যাসের জন্য সমস্ত সম্পত্তি ফেরত পেতে গেটপ্রেটিস ()


99

নিম্নলিখিত অনুমানী উত্তরাধিকারের স্তরক্রমটি ধরে নিচ্ছি:

public interface IA
{
  int ID { get; set; }
}

public interface IB : IA
{
  string Name { get; set; }
}

প্রতিবিম্ব ব্যবহার করে এবং নিম্নলিখিত কল করা:

typeof(IB).GetProperties(BindingFlags.Public | BindingFlags.Instance) 

শুধুমাত্র ইন্টারফেসের বৈশিষ্ট্য অর্জন করবে IB, যা " Name"।

আমরা যদি নিম্নলিখিত কোডটিতে একই রকম পরীক্ষা করে থাকি,

public abstract class A
{
  public int ID { get; set; }
}

public class B : A
{
  public string Name { get; set; }
}

কলটি " " এবং " " এর জন্য অবজেক্টগুলির typeof(B).GetProperties(BindingFlags.Public | BindingFlags.Instance)একটি অ্যারের ফিরিয়ে দেবে ।PropertyInfoIDName

প্রথম উদাহরণ হিসাবে ইন্টারফেসের জন্য উত্তরাধিকার শ্রেণিবিন্যাসের সমস্ত সম্পত্তি খুঁজে পাওয়ার কোন সহজ উপায় আছে?

উত্তর:


111

আমি @ মার্ক গ্রাভেলের উদাহরণ কোডটি একটি কার্যকর এক্সটেনশন পদ্ধতিতে ট্যুইক করেছি যাতে উভয় শ্রেণি এবং ইন্টারফেসকে সংযুক্ত করে। এটি ইন্টারফেসের বৈশিষ্ট্যগুলিও যুক্ত করে যা আমি বিশ্বাস করি প্রত্যাশিত আচরণ।

public static PropertyInfo[] GetPublicProperties(this Type type)
{
    if (type.IsInterface)
    {
        var propertyInfos = new List<PropertyInfo>();

        var considered = new List<Type>();
        var queue = new Queue<Type>();
        considered.Add(type);
        queue.Enqueue(type);
        while (queue.Count > 0)
        {
            var subType = queue.Dequeue();
            foreach (var subInterface in subType.GetInterfaces())
            {
                if (considered.Contains(subInterface)) continue;

                considered.Add(subInterface);
                queue.Enqueue(subInterface);
            }

            var typeProperties = subType.GetProperties(
                BindingFlags.FlattenHierarchy 
                | BindingFlags.Public 
                | BindingFlags.Instance);

            var newPropertyInfos = typeProperties
                .Where(x => !propertyInfos.Contains(x));

            propertyInfos.InsertRange(0, newPropertyInfos);
        }

        return propertyInfos.ToArray();
    }

    return type.GetProperties(BindingFlags.FlattenHierarchy
        | BindingFlags.Public | BindingFlags.Instance);
}

4
খাঁটি তেজ! ধন্যবাদ এই সমস্যার সমাধানটি আমি অপের প্রশ্নের মতোই ছিল।
কমুই

4
বাইন্ডিংফ্লাগস.ফ্লেটেন হাইয়ার্কি সম্পর্কিত আপনার রেফারেন্সগুলি অপ্রয়োজনীয় কারণ আপনি বেন্ডিংফ্লাগস.ইনস্ট্যান্সও ব্যবহার করছেন।
ক্রিস ওয়ার্ড

4
আমি এটি প্রয়োগ করেছি তবে একটি এর Stack<Type>পরিবর্তে Queue<>। স্ট্যাক সহ, পূর্বপুরুষ একটি আদেশ বজায় রাখে interface IFoo : IBar, IBazযেখানে IBar : IBubbleএবং 'আইবাজ: আইফ্লুবার , the order of reflection becomes: আইবার , আইব্বল , আইবাজ , আইফ্লুবার , আইফুও `
IAbstract

4
গেটইন্টারফেসগুলি () ইতিমধ্যে কোনও ধরণের দ্বারা প্রয়োগ করা সমস্ত ইন্টারফেস ফেরত দেয় বলে পুনরাবৃত্তি বা সারিগুলির প্রয়োজন নেই। মার্ক দ্বারা উল্লিখিত হিসাবে, কোন শ্রেণিবদ্ধতা নেই, তাই কেন আমাদের কোনও কিছুর উপর "পুনরাবৃত্তি" করতে হবে?
গ্লোপস

4
যে তুমি কেন ব্যবহার করবেন না @FrankyHollywood GetProperties। আপনি GetInterfacesআপনার প্রারম্ভিক প্রকারে ব্যবহার করুন যা সমস্ত ইন্টারফেসের সমতল তালিকা ফিরে আসবে এবং GetPropertiesপ্রতিটি ইন্টারফেসে কেবল তা করবে। পুনরাবৃত্তি দরকার নেই। ইন্টারফেসে কোনও উত্তরাধিকার বা বেস ধরণের নেই।
গ্লোপস

80

Type.GetInterfaces সমতল শ্রেণিবিন্যাস ফেরত দেয়, তাই পুনরাবৃত্ত বংশোদ্ভূত উত্থানের প্রয়োজন নেই।

লিনকিউ ব্যবহার করে পুরো পদ্ধতিটি আরও সংক্ষিপ্তভাবে লেখা যেতে পারে:

public static IEnumerable<PropertyInfo> GetPublicProperties(this Type type)
{
    if (!type.IsInterface)
        return type.GetProperties();

    return (new Type[] { type })
           .Concat(type.GetInterfaces())
           .SelectMany(i => i.GetProperties());
}

8
এটি অবশ্যই সঠিক উত্তর হওয়া উচিত! আড়ম্বরপূর্ণ পুনরাবৃত্তি প্রয়োজন হয় না।
গ্লোপস

দৃ answer় উত্তর আপনাকে ধন্যবাদ। বেস ইন্টারফেসে আমরা কীভাবে কোনও সম্পত্তির মূল্য পেতে পারি?
ইলিকার আনল

4
@ ইলকারুনাল: সাধারন উপায়: প্যারামিটার হিসাবে আপনার দৃষ্টান্তটি (যার সম্পত্তির মূল্য পেতে হবে) পাস GetValueকরে পুনরুদ্ধার করে on PropertyInfoউদাহরণ: within var list = new[] { 'a', 'b', 'c' }; var count = typeof(IList).GetPublicProperties().First(i => i.Name == "Count").GetValue(list);3 প্রদান করবে, যদিও এর Countমধ্যে সংজ্ঞায়িত করা হয়েছে ICollection, না IList
ডগলাস

4
এই সমাধানটিতে ত্রুটি রয়েছে কারণ এটি একাধিকবার একই নামের বৈশিষ্ট্যগুলি ফিরিয়ে দিতে পারে। স্বতন্ত্র সম্পত্তি তালিকার জন্য ফলাফলের আরও পরিষ্কারের প্রয়োজন needed স্বীকৃত উত্তর হ'ল আরও সঠিক সমাধান কারণ এটি অনন্য নাম সহ সম্পত্তি ফেরত দেওয়ার গ্যারান্টি দেয় এবং উত্তরাধিকার শৃঙ্খলের নিকটতম একটিকে দখল করে এটি করে।
ব্যবহারকারী 3524983

4
@ অ্যান্টওয়াটারগুলি GetInterfaces যদি শ্রেণি হয় তবে এটির প্রয়োজন হয় না type, কারণ কংক্রিট শ্রেণি অবশ্যই উত্তরাধিকার শৃঙ্খলে সমস্ত ইন্টারফেসে সংজ্ঞায়িত সমস্ত বৈশিষ্ট্য প্রয়োগ করতে হবে । ব্যবহার GetInterfacesকরে দৃশ্যকল্প মধ্যে স্থাপিত হবে সব বৈশিষ্ট্য সদৃশ হচ্ছে।
ক্রিস শ্যাচলার

15

ইন্টারফেস হায়ারারচিগুলি একটি ব্যথা - এগুলি সত্যিকার অর্থে "উত্তরাধিকারী" হয় না, যেহেতু আপনার একাধিক "পিতা-মাতা" থাকতে পারে (আরও ভাল সময়ের জন্য)।

"সমতলকরণ" (আবার পুরোপুরি সঠিক শব্দ নয়) হায়ারার্কিতে ইন্টারফেস যে সমস্ত ইন্টারফেস প্রয়োগ করে এবং সেখান থেকে কাজ করছে তা পরীক্ষা করতে পারে ...

interface ILow { void Low();}
interface IFoo : ILow { void Foo();}
interface IBar { void Bar();}
interface ITest : IFoo, IBar { void Test();}

static class Program
{
    static void Main()
    {
        List<Type> considered = new List<Type>();
        Queue<Type> queue = new Queue<Type>();
        considered.Add(typeof(ITest));
        queue.Enqueue(typeof(ITest));
        while (queue.Count > 0)
        {
            Type type = queue.Dequeue();
            Console.WriteLine("Considering " + type.Name);
            foreach (Type tmp in type.GetInterfaces())
            {
                if (!considered.Contains(tmp))
                {
                    considered.Add(tmp);
                    queue.Enqueue(tmp);
                }
            }
            foreach (var member in type.GetMembers())
            {
                Console.WriteLine(member.Name);
            }
        }
    }
}

7
আমি একমত নই মার্কের প্রতি সমস্ত প্রাপ্য সম্মানের সাথে, এই উত্তরটি উপলব্ধি করতেও ব্যর্থ হয় যে getInterfaces () ইতিমধ্যে প্রয়োগ করা সমস্ত ইন্টারফেস একধরণের জন্য প্রদান করে। অবশ্যই কোনও "শ্রেণিবিন্যাস" না থাকায় পুনরাবৃত্তি বা সারিগুলির প্রয়োজন নেই for
গ্লোপস

আমি ভাবছি যদি একটি ব্যবহার HashSet<Type>জন্য consideredব্যবহার বেশী ভালো List<Type>এখানে? একটি তালিকার অন্তর্ভুক্ত রয়েছে একটি লুপ, এবং সেই লুপটি একটি ফোরচ লুপে রাখা হয়েছে, আমি বিশ্বাস করি যে পর্যাপ্ত আইটেম থাকলে এবং কার্য সম্পাদনকে গুরুতরভাবে দ্রুত করা উচিত তবে পারফরম্যান্সে ক্ষতি হবে।
নিরাশ

3

ঠিক একই সমস্যাটির এখানে বর্ণিত একটি কর্মক্ষেত্র রয়েছে ।

ফ্ল্যাটেন হাইয়ারকি বিটিডব্লিউ কাজ করে না। (শুধুমাত্র স্ট্যাটিক ভার্সে। ইন্টেলিজেন্সে তাই বলে)

কর্মক্ষেত্র। সদৃশ থেকে সাবধান।

PropertyInfo[] pis = typeof(IB).GetProperties(BindingFlags.Public | BindingFlags.Instance);
Type[] tt = typeof(IB).GetInterfaces();
PropertyInfo[] pis2 = tt[0].GetProperties(BindingFlags.Public | BindingFlags.Instance);

2

@ ডগলাস এবং @ ব্যবহারকারী 3524983 তে প্রতিক্রিয়া জানাতে, নীচেরগুলিতে ওপি-র প্রশ্নের উত্তর দেওয়া উচিত:

    static public IEnumerable<PropertyInfo> GetPropertiesAndInterfaceProperties(this Type type, BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance)
    {
        if (!type.IsInterface) {
            return type.GetProperties( bindingAttr);
        }

        return type.GetInterfaces().Union(new Type[] { type }).SelectMany(i => i.GetProperties(bindingAttr)).Distinct();
    }

বা, একটি পৃথক সম্পত্তি জন্য:

    static public PropertyInfo GetPropertyOrInterfaceProperty(this Type type, string propertyName, BindingFlags bindingAttr = BindingFlags.Public|BindingFlags.Instance)
    {
        if (!type.IsInterface) {
            return type.GetProperty(propertyName, bindingAttr);
        }

        return type.GetInterfaces().Union(new Type[] { type }).Select(i => i.GetProperty( propertyName, bindingAttr)).Distinct().Where(propertyInfo => propertyInfo != null).Single();
    }

ঠিক আছে পরের বারের পরে :-) এর পরিবর্তে পোস্ট করার আগে আমি এটি ডিবাগ করব


1

এটি কাস্টম এমভিসি মডেল বাইন্ডারে আমার জন্য সুন্দর এবং নিবিড়ভাবে কাজ করেছে। যদিও কোনও প্রতিচ্ছবি দৃশ্যে এক্সট্রোপোলেট করতে সক্ষম হওয়া উচিত। এখনও দুর্গন্ধযুক্ত যে এটি খুব পাস

    var props =  bindingContext.ModelType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).ToList();

    bindingContext.ModelType.GetInterfaces()
                      .ToList()
                      .ForEach(i => props.AddRange(i.GetProperties()));

    foreach (var property in props)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.