6

Situation: Type baseType known only at runtime. objectInstance is a child of type baseType objectInstance was retrieved from a call to a dynamic method

Required:

Type baseType = ...; // obtained at runtime
var baseDynamicInstance = (basetype) objectInstance; // or reflection cast

when hardcoded, it works

   var oi = (PartnerBase) objectInstance;   // this works

tried:

public object CastPocoInstance(Type targetType, object objectInstance) {
    MethodInfo castMethod = objectInstance.GetType().GetMethod("Cast").MakeGenericMethod(targetType); // <<< NULL REF here
    object castedObject = castMethod.Invoke(null, new object[] { objectInstance });
    return castedObject;
   }

ERROR: null object ref error.
in immediate window i see objectInstance.GetType().GetMethod("Cast") returns null
objectInstance.GetType.GetMethods() // shows a list in immediate window. // no cast method shown

I have looked at many examples That would suggest to me the Type.GetMethod("Cast") was correct. But it doesnt work.So clearly im doing something wrong.

Any tips

EDIT: The call error without the down cast to base hardcoded

[Microsoft.CSharp.RuntimeBinder.RuntimeBinderException] = {"The best overloaded method match for 'P42.RepositoryBase.GetEntityState(P42.Core.PartnerBase)' has some invalid arguments"}

EDIT2: AN ObjectInstance is retrieved from a dynamic method call. The object should be used in a call to a dynamic method. If I hard code down cast it works. var x = (baseobject) ObjInstance And call the dynamic method using x. it Works.

The base type is also only known at runtime. Is there a way to cast SpecificObject to BAseObject dynamically?

phil soady
  • 11,043
  • 5
  • 50
  • 95
  • What Cast method are you talking about? Does your object have such a method? – usr Oct 05 '13 at 17:20
  • 1
    What's the point of this? Can you provide background to what you're actually trying to achieve? – spender Oct 05 '13 at 17:20
  • 3
    Since you don't know the type at compile time, I assume you're going to interact with the object using reflection/dynamic, in which case there would be no point or need to cast it, the object is of the type it is regardless. Casting is only useful for types you know to get type safe interaction with the object. – Chris Oct 05 '13 at 17:24
  • 1
    `Cast` is an extension method available for classes implementing `IEnumerable` like `List` and not available for simple concrete classes. – Rohit Vats Oct 05 '13 at 17:25
  • @ Chris, I which that was so. The library being called is called dynamically and the calls crashes with a dynamic call error. When casted prior the call works. – phil soady Oct 05 '13 at 17:27
  • I suggest you check what you pass to the call then - that error message pretty clearly states it can't find a matching overload..! – Chris Oct 05 '13 at 17:33
  • @ Chris If I add var oi = (PartnerBase) objectInstance; and call with oi instead of ObjectInstance it works. – phil soady Oct 05 '13 at 17:35
  • Let's say you could cast your object to a type given at runtime - how would you use it? – Adi Lester Oct 05 '13 at 17:36
  • 1
    Could you edit and show us the method you're trying to call, as well as with what arguments you're calling it? – Chris Oct 05 '13 at 17:36
  • What is the XY problem? http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem Take a read, then tell us what you're actually trying to do. – spender Oct 05 '13 at 17:37
  • @ Adi Lester, I would make the dynamic library call sucessfully. Thats how I would use it. – phil soady Oct 05 '13 at 17:37
  • edited to better explain ( i hope) the problem – phil soady Oct 05 '13 at 17:42
  • In other words you need to cast in order to gain access to a different overloaded method from the one automatically selected by the compiler? – Cosmin Prund Oct 05 '13 at 17:43
  • You should post the actual failing code, not the error message alone; The one you aim to fix by casting to a different type at runtime. – Cosmin Prund Oct 05 '13 at 17:44
  • 1
    We need the complete prototype of the method you're trying to call, and with what types of arguments you're trying to call it. But also, I agree with spender. You should post a new question "Why doesnt this dynamic method call work?" instead. – Chris Oct 05 '13 at 17:45
  • Ok I will build small sample and post that – phil soady Oct 05 '13 at 17:53
  • I tried doing the same thing to initialize the object and type in a switch and then use the type to cast the object and in a loop outside of the switch, thought it was clever but the compiler doesn't recognize that the Type variable will be a type at runtime, or I don't recognize the difference between a variable of a type and the type itself. – user314321 Nov 10 '15 at 15:41

1 Answers1

5

Casting to a type that's known only at Runtime seems to be a senseless operation for the compiler: since by definition it doesn't know the type until Runtime, there's no compile-time support for it so there's no benefit in doing so. If the object is used through Reflection, then the actual Type of the variable that holds the instance doesn't matter much - might as well be Object.

That doesn't mean it's not possible, it's just a bit cumbersome to do the cast. The language does allow us to write code that's only made aware of a given type at Runtime, using type-parametrised types!

The code in my example sets a very simple method to obtain an AdapterDelegate for a LibraryDelegate<TRunTimeType>, using information exclusively found at runtime. You'll notice the actual cast to TRunTimeType in the AdapterDelegateHelper.Adapter<TRuntimeType>.adapter method. Look at the Main code to see how easy this is to use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Reflection;

namespace ConsoleApplication2
{
    // Start by declaring a delegate that looks exactly like the library method you want to call, but with TRuntimeType in place of the actual type
    public delegate void LibraryDelegate<TRuntimeType>(TRuntimeType param, Int32 num, String aStr);
    // Declare an "adapter" delegate that uses "Object" in place of TRuntimeType for every relevant parameter
    public delegate void AdapterDelegate(Object param, Int32 num, String aStr);

    public static class AdapterDelegateHelper
    {
        private class Adapter<TRuntimeType>
        {
            private readonly LibraryDelegate<TRuntimeType> libDelegate;

            public Adapter(Object LibraryInstance, String MethodName)
            {
                Type libraryType = LibraryInstance.GetType();
                Type[] methodParameters = typeof(LibraryDelegate<TRuntimeType>).GetMethod("Invoke").GetParameters().Select(p => p.ParameterType).ToArray();
                MethodInfo libMethod = libraryType.GetMethod(MethodName, methodParameters);
                libDelegate = (LibraryDelegate<TRuntimeType>) Delegate.CreateDelegate(typeof(LibraryDelegate<TRuntimeType>), LibraryInstance, libMethod);
            }

            // Method that pricecly matches the adapter delegate
            public void adapter(Object param, Int32 num, String aStr)
            {
                // Convert all TRuntimeType parameters.
                // This is a true conversion!
                TRuntimeType r_param = (TRuntimeType)param;

                // Call the library delegate.
                libDelegate(r_param, num, aStr);
            }
        }

        public static AdapterDelegate MakeAdapter(Object LibraryInstance, String MethodName, Type runtimeType)
        {
            Type genericType = typeof(Adapter<>);
            Type concreteType = genericType.MakeGenericType(new Type[] { runtimeType });
            Object obj = Activator.CreateInstance(concreteType, LibraryInstance, MethodName);
            return (AdapterDelegate)Delegate.CreateDelegate(typeof(AdapterDelegate), obj, concreteType.GetMethod("adapter"));
        }
    }

    // This class emulates a runtime-identified type; I'll only use it through reflection
    class LibraryClassThatIOnlyKnowAboutAtRuntime
    {
        // Define a number of oberloaded methods to prove proper overload selection
        public void DoSomething(String param, Int32 num, String aStr)
        {
            Console.WriteLine("This is the DoSomething overload that takes String as a parameter");
            Console.WriteLine("param={0}, num={1}, aStr={2}", param, num, aStr);
        }

        public void DoSomething(Int32 param, Int32 num, String aStr)
        {
            Console.WriteLine("This is the DoSomething overload that takes Integer as a parameter");
            Console.WriteLine("param={0}, num={1}, aStr={2}", param, num, aStr);
        }

        // This would be the bad delegate to avoid!
        public void DoSomething(Object param, Int32 num, String aStr)
        {
            throw new Exception("Do not call this method!");
        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            Type castToType = typeof(string);
            Type libraryTypeToCall = typeof(LibraryClassThatIOnlyKnowAboutAtRuntime);

            Object obj = Activator.CreateInstance(libraryTypeToCall);

            AdapterDelegate ad1 = AdapterDelegateHelper.MakeAdapter(obj, "DoSomething", castToType);
            ad1("param", 7, "aStr");

            Console.ReadKey();
        }
    }
}
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
  • 2
    Im going over old posts. I didn't end finding a way to do what i wanted and reworked a lot of code. The comment regarding the compiler and this example make sense to me. Although I didnt use the sample, I appreciate the effort Cosmin – phil soady Mar 13 '15 at 07:59