how to dynamically cast IList to Array of an arbitrary datatype using Reflection

Viewed 126
class myClass1
{
    public string obj1;
    public string obj2;

}
class myClass2
{
    public myClass1[] fArray = new myClass1[1];
    public string str;
}
class Program
{
    static void Main(string[] args)
    {
        string mytype = "ConsoleApp3.myClass2";
        Type type = Type.GetType(mytype);
        object myObj = Activator.CreateInstance(type);
        FieldInfo fi = type.GetField("fArray");
        Type type2 = fi.FieldType.GetElementType();
        object newObj;
        IList list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(fi.GetValue(myObj).GetType().GetElementType()));
        {
            newObj = Activator.CreateInstance(type2);
            FieldInfo fi2 = type2.GetField("obj1");
            fi2.SetValue(newObj, "some txt1");
            FieldInfo fi3 = type2.GetField("obj2");
            fi3.SetValue(newObj, "some txt2");
            list.Add(newObj);
        }

        {
            newObj = Activator.CreateInstance(type2);
            FieldInfo fi2 = type2.GetField("obj1");
            fi2.SetValue(newObj, "some txt1");
            FieldInfo fi3 = type2.GetField("obj2");
            fi3.SetValue(newObj, "some txt2");
            list.Add(newObj);

        }

        fi.SetValue(myObj, list.Cast<myClass1>().ToArray());

The Code above is working fine. In my usecase "myClass1" is not know at the compile time. I am receiving the type of myClass1 as a string at runtime.

How can I cast a list to array of type myClass1 using reflection?

        fi.SetValue(myObj, list.Cast<???>().ToArray());
2 Answers

You can make generic methods too:

Let's create a local variable for the element type so we can reuse it.

var elementType = fi.GetValue(myObj).GetType().GetElementType();
...

Get the cast method and the array method from the linq enumerable class.

var castMethod = typeof(System.Linq.Enumerable).GetMethod("Cast").MakeGenericMethod(elementType);
var arrayMethod = typeof(System.Linq.Enumerable).GetMethod("ToArray").MakeGenericMethod(elementType);

Call the methods with null as the first argument for static methods.

var casted = castMethod.Invoke(null, new[] { list });
var array = arrayMethod.Invoke(null, new[] { casted });
fi.SetValue(myObj, array);

There may be a smarter way of doing this, but this might get you started.

Type.GetType and Type.MakeArrayType comes to your aid.

You can do:

Type t = Type.GetType("myString");

or

Type arrayT = Type.GetType("myString").MakeArrayType() ;

In your example, GetType would be enough, but it's good to know about MakeArrayType as well.

Related