문제
리플렉션을 사용하여 컬렉션을 반복하는 방법이 있습니까(바람직하게는 foreach를 통해)?리플렉션을 사용하여 개체의 속성을 반복하고 있으며 프로그램이 컬렉션 형식에 도달하면 컬렉션의 콘텐츠를 반복하고 컬렉션의 개체에 액세스할 수 있기를 바랍니다.
현재 모든 속성에 특성이 설정되어 있고 컬렉션인 속성에 IsCollection 플래그가 true로 설정되어 있습니다.내 코드는 이 플래그를 확인하고 그것이 true이면 리플렉션을 사용하여 유형을 가져옵니다.항목을 반복할 수 있도록 컬렉션에서 GetEnumerator 또는 Items를 호출하는 방법이 있습니까?
해결책
이 문제가 있었지만 리플렉션을 사용하는 대신 IEnumerable인지 확인하게 되었습니다.모든 컬렉션이 이를 구현합니다.
if (item is IEnumerable)
{
foreach (object o in (item as IEnumerable))
{
}
} else {
// reflect over item
}
다른 팁
나는 Darren이 제안한 것과 유사한 기술을 사용하려고 시도했지만 컬렉션만이 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.Invoke() (?) 메서드를 사용하여 새 인스턴스를 만들거나 해당 유형의 인스턴스를 가리킵니다.
Type.FindInterfaces 메서드를 살펴보겠습니다.이는 특정 유형으로 구현된 인터페이스를 필터링할 수 있습니다.PropertyInfo.PropertyType.FindInterfaces(filterMethod, filterObjects)에서와 같습니다.IEnumerable로 필터링하고 결과가 반환되는지 확인할 수 있습니다.MSDN에는 메소드 문서에 훌륭한 예가 있습니다.
객체의 인스턴스를 사용하지 않고 유형을 사용하는 경우 다음을 사용할 수 있습니다.
// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}
다소 간단한 접근 방식은 개체를 컬렉션으로 형식 변환하여 직접 사용하는 것입니다.