-1

I'm trying to call a method with reflection. This is the class:

public class MyData<T> where T : struct
{
    public void CopyFrom(T[] array)
    { /* code */ }
}

Now I have an array that contains the objects that I want to put into the class, but my objects are boxed.

var container = new MyData<int>();
var method = typeof(MyData<>).GetMethod("CopyFrom");
object[] boxed = new object[] {1, 2, 3};
method.Invoke(container, new object[] { boxed });

The error that I get is this: System.ArgumentException: Object of type 'System.Object[]' cannot be converted to type 'T[]'.

What is the right way to call this method?

Note that this is not a generic method. So it's not duplicate of How do I use reflection to call a generic method?

PNarimani
  • 614
  • 7
  • 23
  • Asking the [exact same question](https://stackoverflow.com/questions/60689029/argumentexception-on-method-invocation-object-of-type-system-object-cannot) is not the right way to do this. You're better off editing your original question so that it's viable to be reopened. – Zer0 Mar 15 '20 at 03:35
  • @Zer0 Quickly closing questions before reading them is not right too. Also my question didn't need any editing. It shouldn't have been closed in the first place. – PNarimani Mar 15 '20 at 03:44
  • I don't disagree. I have voted to reopen questions. But I also don't think it's good practice to simply re-post a question because it's closed. Maybe someone with better knowledge can tell you exactly what steps you should take. – Zer0 Mar 15 '20 at 03:47

1 Answers1

2

You could do the following

public void InvokeCopyFrom(Type genericType,object[] parameters)
{
    //Create BoundedGenericType
    var openGeneric = typeof(MyData<>);
    var boundGenericType = openGeneric.MakeGenericType(genericType);

    // Create instance based on bounded type
    var container = Activator.CreateInstance(boundGenericType);

    // Get MethodInfo from Bounded Type
    var method = boundGenericType.GetMethod("CopyFrom");

    // Cast the boxed parameter collection
    var listType = typeof(List<>).MakeGenericType(genericType);
    var arrayOfDestinationType = this.GetType()
                             .GetMethod("CastAsArray")
                             .MakeGenericMethod(listType.GetGenericArguments().First())
                             .Invoke(this, new[] {parameters});
    // Invoke the method
    method.Invoke(container,new object[]{arrayOfDestinationType});
}

Where CastAsArray is defined as

public T[] CastAsArray<T>(object[] source)
{
    var result = new List<T>();
    foreach (var item in source)
    {
       result.Add((T)Convert.ChangeType(item, typeof(T)));
    }
    return result.ToArray();
}
Anu Viswan
  • 17,797
  • 2
  • 22
  • 51
  • I don't know the type 'int' in compile time. So I cannot do `Cast()`. The only thing that I have is the `System.Type` that corresponds to type (i.e: typeof(int)). Is it possible to do casting given an instance of `System.Type`? – PNarimani Mar 15 '20 at 04:01
  • 1
    I also called `Cast<>()` and `ToArray()` methods with reflection and it worked. I'm marking this as answer but it would be nice if you added these too for future searches. – PNarimani Mar 15 '20 at 04:18
  • `var container = new MyData();` depends on type `int` here... so the improved version of this code with `Cast<>` and `ToArray()` will work as long as it is `MyClass`. If you change this to `MyClass` it will not work with array of object with `int` values in it. And if you know the type of values in object then you don't need to reflection on it. – Chetan Mar 15 '20 at 04:28
  • @ChetanRanpariya Please check the updated answer – Anu Viswan Mar 15 '20 at 04:56
  • @AnuViswan You nailed it right there... properly fitting answer... Upvoted. – Chetan Mar 15 '20 at 05:05