0

I am analyzing code files that have unkown object and unkown container classes with Reflection.

Example of Object Class to find:

 class Object
{
    public string Name{ get; set; }

    public Travel(string Name)
    {
        this.Name= Name;
    }
}

Example of Container Class to find:

class Container
{
    List<Object> list = new List<Object>();
    public Container(List<Object> objects)
    {
        foreach (Object object in objects)
        {
            list.Add(object);
        }
    }

The code my program analyzes has to find an Object Class and a Container Class.

I want to access list from Container Class.

Using Reflection at runtime I can get Object Class and Container Class Types.

I have this method to get FieldInfo

public FieldInfo GetFieldByType(Type type, string typeName)
    {
        foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static))
        {
            if (fi.FieldType.ToString().Contains(typeName))
                return fi;
        }
        return null;
    }

Using

FieldInfo list = _parser.GetFieldByType(_ContainerClass, "System.Collections.Generic.List");

passing Container Type I get list's FieldInfo.

My question is:

How to get List<(uknown class)> from FieldInfo or maybe cast it to be List<> so that I could get for example List.Count or List containing objects at runtime?

Or do I need to use PropertyInfo to achieve this?

  • 1
    Can you give a more concrete example of how you would use this method (with inputs), and your expected and actual results? – gunr2171 Mar 30 '22 at 18:18
  • https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.tolist?view=net-6.0 – Hans Passant Mar 30 '22 at 18:18
  • @gunr2171 I want to get from Container Class a List with FieldInfo when ObjectClass is unkwon and it's Type is found at runtime. – jonas balsys Mar 30 '22 at 18:46
  • `Object` is a particularly poor name for a sample class as that already exists, obviously, and `List` is certainly valid as a generic container, but very different from `List`. – Jeroen Mostert Mar 30 '22 at 19:12

1 Answers1

0

All collections can be cast to IEnumerable, so just check if it can be assigned to an IEnumerable. If it is, cast it. In this example all I do is take a count but you could also iterate over the data if you want.

public static int GetCount(object container)
{
    var fields = container
        .GetType()
        .GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public );
    var collectionFields = fields
        .Where
        ( 
            x => typeof(IEnumerable).IsAssignableFrom(x.FieldType)
        )
        .ToList();
    if (collectionFields.Count != 1)
    {
        //If there isn't exactly one field, we don't know how to get a count
        return -1; 
    }
    else
    {
        var collectionField = collectionFields.Single();
        var collection = collectionField.GetValue(container) as IEnumerable;
        return collection.Cast<object>().Count();
    }
}
John Wu
  • 50,556
  • 8
  • 44
  • 80
  • I tried your function, but it returned -1. How do i get container with Reflection? I can get container's Type, but casting it to object does not help, I get error (allTravels is the List<>) : Field 'allTravels' defined on type 'Kontrolinis.TravelAgency' is not a field on the target object which is of type 'System.RuntimeType'. – jonas balsys Mar 31 '22 at 16:40
  • The implementation [works fine](https://dotnetfiddle.net/9qP32C) in DotNetFiddle. You may have to step through your code to see why it isn't finding the fields. It's possible you made a mistake in the way you defined the class, e.g. maybe it has more than one field that could be a collection, or maybe you used a property instead of a field. – John Wu Mar 31 '22 at 17:59
  • How do you get object container which you pass to this function? – jonas balsys Apr 03 '22 at 08:00