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?
Dynamic types are similar to object types except that type checking for object type variables takes place at compile time, whereas that for the dynamic type variables takes place at runtime.
For example: Type intType = typeof(Int32); object value1 = 1000.1; // Variable value2 is now an int with a value of 1000, the compiler // knows the exact type, it is safe to use and you will have autocomplete int value2 = Convert.
In C# 4.0, a new type is introduced that is known as a dynamic type. It is used to avoid the compile-time type checking. The compiler does not check the type of the dynamic type variable at compile time, instead of this, the compiler gets the type at the run time.
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();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With