سؤال

هل هناك طريقة للتكرار (يفضل من خلال foreach) على مجموعة باستخدام الانعكاس؟أقوم بالتكرار على الخصائص الموجودة في كائن ما باستخدام الانعكاس، وعندما يصل البرنامج إلى نوع يمثل مجموعة، أود أن يتكرر على محتويات المجموعة ويكون قادرًا على الوصول إلى الكائنات الموجودة في المجموعة.

في الوقت الحالي، لدي سمة تم تعيينها على جميع خصائصي، مع تعيين علامة IsCollection على القيمة true على الخصائص التي تمثل مجموعات.يتحقق الكود الخاص بي من هذه العلامة وإذا كانت صحيحة، فسيحصل على النوع باستخدام الانعكاس.هل هناك طريقة لاستدعاء GetEnumerator أو العناصر بطريقة أو بأخرى في مجموعة لتتمكن من التكرار على العناصر؟

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

المحلول

لقد واجهت هذه المشكلة، ولكن بدلاً من استخدام الانعكاس، انتهى بي الأمر بالتحقق مما إذا كان IEnumerable.جميع المجموعات تنفذ ذلك.

if (item is IEnumerable)
{
    foreach (object o in (item as IEnumerable))
    {

    }
} else {
   // reflect over item
}

نصائح أخرى

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

إليك وظيفة صغيرة أستخدمها لتحديد ما إذا كان الكائن عبارة عن مجموعة (والتي ستكون قابلة للتعداد أيضًا نظرًا لأن ICollection هو أيضًا IEnumerable).

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }

ما عليك سوى الحصول على قيمة الخاصية ثم تحويلها إلى IEnumerable.إليك بعض التعليمات البرمجية (غير المختبرة) لإعطائك فكرة:

ClassWithListProperty obj = new ClassWithListProperty();
obj.List.Add(1);
obj.List.Add(2);
obj.List.Add(3);

Type type = obj.GetType();
PropertyInfo listProperty = type.GetProperty("List", BindingFlags.Public);
IEnumerable listObject = (IEnumerable) listProperty.GetValue(obj, null);

foreach (int i in listObject)
    Console.Write(i); // should print out 123

أفضل ما يمكنك فعله هو التحقق مما إذا كان الكائن يطبق واجهات تجميع معينة - ربما يكون IEnumerable هو كل ما تحتاجه.بعد ذلك، كل ما عليك فعله هو استدعاء GetEnumerator() خارج الكائن، واستخدام IEnumerator.MoveNext() و IEnumerator.Current للعمل في المجموعة.

لن يساعدك هذا إذا كانت المجموعة لا تنفذ تلك الواجهات، ولكن إذا كان الأمر كذلك، فهي ليست مجموعة كبيرة حقًا، على ما أعتقد.

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

 public void LogObject(object obj, int indent)
    {
        if (obj == null) return;
        string indentString = new string(' ', indent);
        Type objType = obj.GetType();
        PropertyInfo[] properties = objType.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            Type tColl = typeof(ICollection<>);
            Type t = property.PropertyType;
            string name = property.Name;


            object propValue = property.GetValue(obj, null); 
            //check for nested classes as properties
            if (property.PropertyType.Assembly == objType.Assembly)
            {
                string _result = string.Format("{0}{1}:", indentString, property.Name);
                log.Info(_result);
                LogObject(propValue, indent + 2);
            }
            else
            {
                string _result = string.Format("{0}{1}: {2}", indentString, property.Name, propValue);
                log.Info(_result);
            }

            //check for collection
            if (t.IsGenericType && tColl.IsAssignableFrom(t.GetGenericTypeDefinition()) ||
                t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == tColl))
            {
                //var get = property.GetGetMethod();
                IEnumerable listObject = (IEnumerable)property.GetValue(obj, null);
                if (listObject != null)
                {
                    foreach (object o in listObject)
                    {
                        LogObject(o, indent + 2);
                    }
                }
            }
        }
    }

وتسمى هذه الوظيفة

LogObject(obj, 0);

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

عندما تستخدم الانعكاس، فإنك لا تستخدم بالضرورة مثيلًا لهذا الكائن.سيتعين عليك إنشاء مثيل من هذا النوع لتتمكن من التكرار من خلال خصائص الكائن.لذا، إذا كنت تستخدم الانعكاس، فاستخدم طريقة ConstructorInfo.Invoc() (؟) لإنشاء مثيل جديد أو الإشارة إلى مثيل من النوع.

سألقي نظرة على طريقة Type.FindInterfaces.يمكن أن يؤدي ذلك إلى تصفية الواجهات التي ينفذها نوع معين.كما هو الحال في PropertyInfo.PropertyType.FindInterfaces(filterMethod, filterObjects).يمكنك التصفية حسب IEnumerable ومعرفة ما إذا تم إرجاع أية نتائج.لدى MSDN مثال رائع في وثائق الطريقة.

إذا كنت لا تستخدم مثيلًا للكائن، بل تستخدم النوع، فيمكنك استخدام ما يلي:

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}

قد يكون الأسلوب المباشر إلى حد ما هو كتابة الكائن كمجموعة واستخدامه مباشرة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top