I have this class:
internal class MyClass
{
string name { get; set; }
List<MyClass2> myClass2 { get; set; }
}
where MyClass2
:
internal MyClass2
{
string field1 { get; set; }
string field2 { get; set; }
int field3 { get; set; }
long field4 { get; set; }
}
I want to retrieve the fields of the myClass2
via reflection, so I coded the snippet below:
Type objectType = typeof(MyClass);
IEnumerable<MemberInfo> members = objectType
.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(p => p.MemberType == MemberTypes.Property);
foreach (var field in members)
{
if (field.Name != "name")
{
var fieldT = field.GetType();
Console.WriteLine("Field: " + field.Name + "; Field type: " + typeof(Property));
Type propertiesType = field.GetType();
IEnumerable<MemberInfo> propertiesMembers = typeof(Property)
.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(p => p.MemberType == MemberTypes.Property);
foreach(var property in propertiesMembers)
{
Console.WriteLine("Looking for field: " + field.Name);
var value = fields.Where(f => f.Key == field.Name).First();
Console.WriteLine("Actual value receiver for: " + field.Name + " => " + value);
}
}
}
where fields
it's just a Dictionary<string, dynamic>
containing non interesting data for the question.
The thing is that I am unable to retrieve the fields in the variable myClass2
, first, because it's a collection, and second, because in the fields
variable of the loop, it's determining it's type to System.Reflection.RuntimePropertyInfo
.
How can I modify my code to get a collection of the fields inside myClass2
, yielding the real data that I am looking for? That is just the member info for the MemberTypes
that are MemberTypes.Property
?
Thanks.
The line var fieldT = field.GetType();
isn't doing what you think. field
is a MemberInfo
instance, so field.GetType()
will be the same as typeof(MemberInfo)
.
What you want is the type the property has been declared as, and for that, you'll need to cast to PropertyInfo
first:
Type propertiesType = ((PropertyInfo)field).PropertyType;
From there, you can detect when the property is a List<T>
and reflect over that T
to get the list of properties on it:
foreach (var property in members)
{
if (property.Name != "name")
{
//May be null for some built-in types.
if (property.DeclaringType == null)
continue;
var propInfo = (PropertyInfo)property;
//If this field refers to a List<T>, get the fields of that lists generic type
if (propInfo.PropertyType.IsGenericType
&& typeof(IList<>).MakeGenericType(propInfo.PropertyType.GenericTypeArguments).IsAssignableFrom(propInfo.PropertyType))
{
var fieldType = propInfo.PropertyType.GenericTypeArguments[0];
var genericListTypeFields = fieldType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var innerField in genericListTypeFields)
Console.WriteLine($"Found property {innerField.Name}");
}
}
}
Which outputs:
Found property field1
Found property field2
Found property field3
Found property field4