Как повторять список в отражении
У меня есть одно свойство "Студенты", которое имеет тип List<Student>
.
В отражении я могу получить значение свойства 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>
.
RANT
Вот почему мне лично не нравится var
, он скрывает тип - если только в VS вы не наводите на него курсор. Если он был объявлен с типом object
, сразу стало очевидно, что мы не можем его перебирать.
UPDATE
Да, это хорошо. Но кастинг должен быть сделано с отражением. В отражении мы Не знаю тип списка. Мы не знать фактический тип studentObj
Чтобы сделать это, вы можете использовать IEnumerable
:
var collection = (IEnumerable) studentPro.GetValue(studentObj,null);
Ответ 2
Попробуйте это
IEnumerable<Student> collection = (IEnumerable<Student>)studentPro.GetValue(studentObj,null);
Ответ 3
Другие предложили листинг в List, но я буду считать, что это не сработает для вас... если бы вы имели доступ к классу Student, вы бы не использовали рефлексию для начала. Таким образом, вместо этого просто добавьте в IEnumerable, а затем внутри своего цикла, вам придется снова использовать отражение для доступа к любым свойствам, которые вы хотите от каждого элемента в коллекции.
var collection = (IEnumerable)studentPro.GetValue(studentObj,null)
Ответ 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; }
}