Как выполнить итерацию списка в отражении

#c# #reflection

#c# #отражение

Вопрос:

У меня есть одно свойство, называемое Students, которое имеет тип List<Student> .

В reflection я могу получить значение свойства Students.

Теперь проблема в том, как выполнить итерацию списка студентов.

Мне нужно проверить, есть ли StudentID [некоторое значение] в этой коллекции.

 var collection = studentPro.GetValue(studentObj,null);

//I need to iterate like this,

foreach(var item in collection)
{
     if(item.StudentID == 33)
         //Do stuff
}
  

Пожалуйста, помогите мне.

Ответ №1:

Вам просто нужно привести его:

 var collection = (List<Student>) studentPro.GetValue(studentObj,null);
  

Возвращаемое вам значение, сохраненное в var , имеет тип object . Итак, сначала вам нужно привести его к List<Student> , прежде чем пытаться выполнять цикл по нему.

НАПЫЩЕННАЯ РЕЧЬ

Вот почему мне лично не нравится var , это скрывает тип — если только в VS вы не наведете на него курсор. Если это был объявленный с типом object , сразу было очевидно, что мы не можем выполнить итерацию по нему.


Обновить

Да, это хорошо. Но приведение должно выполняться с помощью reflection. В отражении мы не знаем тип списка. Мы не знаем фактического типа studentObj

Для того, чтобы сделать это, вы можете привести к IEnumerable :

 var collection = (IEnumerable) studentPro.GetValue(studentObj,null);
  

Комментарии:

1. Да, это хорошо. Но приведение должно выполняться с помощью reflection. В отражении мы не знаем тип списка<?>. Мы не знаем фактического типа studentObj.

2. При попытке этого я получаю сообщение об ошибке — Использование универсального типа ‘System. Коллекции. Общий. Для IEnumerable<T>’ требуется 1 аргумент типа.

3. Джаган — Опубликованная вами ошибка очевидна, для нее требуется тип. Кроме того, вам не следует использовать метод, который вы используете, если вы не понимаете, как это сделать (учитывая тот факт, что ваш код концептуально исправляет все, за исключением того факта, что вы забыли привести материал).

4. ОК. В reflection просто рассмотрим, что у меня есть один объект, но не указан его тип. Если этот объект является коллекцией, мне нужно выполнить итерацию и напечатать все значения.

Ответ №2:

Попробуйте это

 IEnumerable<Student> collection = (IEnumerable<Student>)studentPro.GetValue(studentObj,null);
  

Ответ №3:

Другие предлагали использовать приведение к List, но я предполагаю, что у вас это не сработает … если бы у вас был доступ к классу Student, вы бы изначально не использовали reflection. Итак, вместо этого просто приведите к IEnumerable, а затем внутри вашего цикла вам придется снова использовать reflection для доступа к любым свойствам, которые вы хотите от каждого элемента в коллекции.

var collection = (IEnumerable)studentPro.GetValue(studentObj,null)

Комментарии:

1. При попытке этого я получаю сообщение об ошибке — Использование универсального типа ‘System. Коллекции. Общий. Для IEnumerable<T>’ требуется 1 аргумент типа

2. попробуйте (System. Коллекции. IEnumerable)

3. Это решило бы его проблему. Хотя я сомневаюсь в невозможности решить такую простую проблему самостоятельно. Он действительно не должен даже использовать общую коллекцию.

Ответ №4:

То, что вы попробовали, является правильным. Вам просто нужно исправить свой код и привести возвращаемое значение из GetValue :

 var collection = (List<Student>)studentPro.GetValue(studentObj,null);

foreach(var item in collection)
{
     if(item.StudentID == 33)
         //Do stuff
}
  

Ответ №5:

Вы можете использовать что-то вроде приведенного ниже, чтобы создать объект POCO из вашего прокси-объекта. Пожалуйста, обратите внимание, что я полагаюсь на использование атрибута XmlIgnore для разрыва циклических ссылок

 static object DeepCopy(object obj, Type targetType)
    {
        if (obj != null)
        {
            Type t = obj.GetType();

            object objCopy = Activator.CreateInstance(targetType);

            Type copyType = targetType;

            var props =
                t.GetProperties();

                    //.Where(x => x.PropertyType.GetCustomAttributes(typeof(XmlIgnoreAttribute), false).Length == 0);
            foreach (var propertyInfo in props)
            {
                var targetProperty = copyType.GetProperties().Where(x => x.Name == propertyInfo.Name).First();

                if (targetProperty.GetCustomAttributes(typeof(XmlIgnoreAttribute), false).Length > 0)
                {
                    continue;
                }

                if (propertyInfo.PropertyType.IsClass)
                {
                    if (propertyInfo.PropertyType.GetInterface("IList", true)!=null)
                    {
                        var list = (IList)Activator.CreateInstance(targetProperty.PropertyType);

                        targetProperty.SetValue(objCopy,list);

                        var sourceList = propertyInfo.GetValue(obj) as IList;

                        foreach (var o in sourceList)
                        {
                            list.Add(DeepCopy(o, targetProperty.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]));
                        }

                    }
                    else if (propertyInfo.PropertyType == typeof(string))
                    {
                        targetProperty.SetValue(objCopy, propertyInfo.GetValue(obj));
                    }
                    else
                    {
                        targetProperty.SetValue(objCopy, DeepCopy(propertyInfo.GetValue(obj), targetProperty.PropertyType));
                    }

                }
                else
                {
                    targetProperty.SetValue(objCopy,propertyInfo.GetValue(obj));
                }
            }

            return objCopy;

        }
        return null;
    }

    class MyDbContext:DbContext
{
    public MyDbContext():base(@"Server=(LocalDb)v12.0;Trusted_Connection=True;")
    {

    }

    public DbSet<Table1> Table1s { get; set; }

    public DbSet<Table2> Table2s { get; set; }

}

public class Table1
{
    public int ID { get; set; }

    public string name { get; set; }

    virtual public List<Table2> Table2s { get; set; }
}


public class Table2
{
    public int ID { get; set; }

    public string Name { get; set; }
    [XmlIgnore]
    virtual public Table1 Table1 { get; set; }
}