Adriaan
Adriaan

Reputation: 51

Dynamic type casting to a generic list of an internal type

I am using a third party API and I need to access a private field ("_fieldOfB") of an internal field ("_fieldOfA"). The example below illustrates the composition. The field I am looking for is a List of internal types (ClassC and ClassD are internal and in the same assembly).

 public abstract class ClassA
 {
    internal ClassB _fieldOfA;
 }

 public class ClassB
 {
    private readonly List<ClassC<ClassD, int>> _fieldOfB;
 }

I have tried with reflection, but I can't seem to get the final type cast right - the dynamic type stays Object (note that my class extends ClassA)

var assemblyHandle = typeof (ClassB).Assembly;
var genericTypeC = assemblyHandle.GetType("ApiNamespace.ClassC`2");
var typeD = assemblyHandle.GetType("ApiNamespace.ClassD");

var genericTypesForC = new Type[] { typeD, typeof(int) };
var typeC = genericTypeC.MakeGenericType(genericTypesForC);
var typeOfList = typeof(List<>).MakeGenericType(typeC);

var fieldOfAInfo= typeof(ClassA).GetField("_fieldOfA", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
var fieldOfAValue = fieldOfAInfo.GetValue(this);

var fieldOfBInfo= typeof(ClassB).GetField("_fieldOfB", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
var uncastedFieldOfBValue = fieldOfBInfo.GetValue(fieldOfAValue);

dynamic fieldOfBValue = Convert.ChangeType(uncastedFieldOfBValue, typeOfList);

Any ideas?

Upvotes: 2

Views: 1629

Answers (1)

Adam Maras
Adam Maras

Reputation: 26883

Something you can do to more easily access the items in the List<ClassC<ClassD, int>> (after you've cast the object to IList, per the comments) is to use the Enumerable.Cast<TResult> extension method on your list to provide you with an enumeration of dynamic objects; this way, instead of using reflection, you can simply have the runtime bind your calls for you.

IList nonGenericList = uncastedFieldOfBValue as IList;
IEnumerable<dynamic> dynamicEnumerable = nonGenericList.Cast<dynamic>();

foreach (dynamic obj in dynamicEnumerable)
{
    // work with your objects here
}

Of course, this will only allow you to access public methods and properties on instances located in the third-party assembly. If you want to play with the internals, you can look at one of these blog posts to see how to create a DynamicObject wrapper that allows you to bind calls to non-public members using reflection.

Upvotes: 2

Related Questions