Convert Variable to Type Only Known at Run-Time

Convert variable to type only known at run-time?

The types you are using all implement IConvertible. As such you can use ChangeType.

 value = Convert.ChangeType(method.Invoke(null, new[] { value }), paramType);

Dynamic object cast to type known at runtime only

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();
}
}
}

How to cast to a type that is only known at runtime

Thanks to erasure, the type argument of each Foo isn't known at runtime at all.

There is no perfect way to solve this problem, because using generics like this is inherently unsafe. There may be a way to rethink your solution to avoid this altogether (mutating values of star-projected types is generally a bad idea, which is why the type system prevents you from assigning anything but null to values of upper-bounded invariant types.)

You'll have to provide the type itself as an argument to each Foo:

data class Foo<T : Any> (
val type: KClass<T>,
var value: T
)

val foos = listOf<Foo<*>>(
Foo(String::class, value = "I a a String"),
Foo(Int::class, value = 1),
Foo(Boolean::class, value = true)
)

val anyTypes = listOf<Any>("String", 1, false)

...
foos.forEachIndexed { idx, foo ->
@Suppress("UNCHECKED_CAST")
(foo as Foo<Any>).value = foo.type.cast(anyTypes[idx])
}

foos.forEach(::println)

You could also omit the KClass argument and go without the cast, but then you risk silently accepting values of the wrong type, which will only fail when the value is accessed and used.

C# how to cast object to runtime type?

TL;DR

You can't cast something to an unknown type specified at runtime. That would mean that within your code, you don't know what the object's properties or methods are unless you use even more reflection. In that case what would be the point of casting it?


Sometimes we deal with types that aren't known until runtime. But unless the type really doesn't matter at all, the object is useless unless we can cast it to some predetermined type that is specified in our code, not at runtime.

In this line of code:

var val = property.GetValue(obj); 

the declared type of val is inferred by the compiler. That type is object because that's the type that GetValue returns. The actual type of the object could be string, int, List<Foo>, whatever. But you've got a variable val of type object.

If you could do this:

var val = property.GetValue(obj) as runtimeType;    

Then what would the compile-time type of val be? How can it have any, since runTimeType is a runtime value? The object is useless unless you can call methods or inspect its properties. But you can't do that without knowing the type, unless you use more reflection. But if your're going to do that then there's no point in casting it.

Somewhere downstream from the code you've posted you'll presumably want to actually do something with the object that involves its methods or properties. That means knowing what type you think it is and casting it as that type. That would be a type specified in your code, not something determined at runtime.

For example:

var val = property.GetValue(obj); // I know this is a string
var myString = (string)val;
var findX = myString.IndexOf("X");

I think it's a string so I cast it as a string. (There could be additional checks in there.) Now that I've cast it, I've got a variable that's declared as type string, and I can use it as a string. (Unless it wasn't a string - then it will throw a runtime exception.)

That's the benefit of casting - it allows us to assign something to a strongly-typed variable with a type we specify and then use it accordingly. Casting to an unknown type wouldn't benefit us.


At the risk of adding confusion: Someone could say that generics represent types unspecified at runtime, but that's not exactly true. List<T> doesn't specify what T is, but if you create a List<T>, somehow, somewhere you're going to specify the type in your code. In the vast majority of normal scenarios we have to know something about the type of an object or else the object is useless to us.

When is a type only known at runtime?

Here's an example:

use rand::{thread_rng, Rng};

struct ConcreteA { }
struct ConcreteB { }

trait Trait { }

impl Trait for ConcreteA { }
impl Trait for ConcreteB { }

fn main() {
// a runtime value
let cond: bool = thread_rng().gen();

let a = ConcreteA { };
let b = ConcreteB { };

let r: &dyn Trait = if cond { &a } else { &b };
}

What would be the concrete type that r refers to?

Trait constraints are checked by the compiler at the points where the &dyn Trait is created, since it must refer to a concrete type. The rest of the code can use the reference without knowing the concrete type by using dynamic dispatch. So the compiler always knows it refers to a concrete type but not necessarily which one.

C#: Dynamic runtime cast

I think you're confusing the issues of casting and converting here.

  • Casting: The act of changing the type of a reference which points to an object. Either moving up or down the object hierarchy or to an implemented interface
  • Converting: Creating a new object from the original source object of a different type and accessing it through a reference to that type.

It's often hard to know the difference between the 2 in C# because both of them use the same C# operator: the cast.

In this situation you are almost certainly not looking for a cast operation. Casting a dynamic to another dynamic is essentially an identity conversion. It provides no value because you're just getting a dynamic reference back to the same underlying object. The resulting lookup would be no different.

Instead what you appear to want in this scenario is a conversion. That is morphing the underlying object to a different type and accessing the resulting object in a dynamic fashion. The best API for this is Convert.ChangeType.

public static dynamic Convert(dynamic source, Type dest) {
return Convert.ChangeType(source, dest);
}

EDIT

The updated question has the following line:

obj definitely implements castTo

If this is the case then the Cast method doesn't need to exist. The source object can simply be assigned to a dynamic reference.

dynamic d = source;

It sounds like what you're trying to accomplish is to see a particular interface or type in the hierarchy of source through a dynamic reference. That is simply not possible. The resulting dynamic reference will see the implementation object directly. It doesn't look through any particular type in the hierarchy of source. So the idea of casting to a different type in the hierarchy and then back to dynamic is exactly identical to just assigning to dynamic in the first place. It will still point to the same underlying object.



Related Topics



Leave a reply



Submit