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.
Why is casting with dynamic faster than with object
You can have a look at IL code to see the difference under the hood. Object cast
public TEnum ObjectCast()
{
return (TEnum)(object)0;
}
box int
value into object
and then unbox into TEnum
value, since it's value type
IL_0001: ldc.i4.0
IL_0002: box [System.Runtime]System.Int32
IL_0007: unbox.any TestConsoleApp.Test/TEnum
IL_000c: stloc.0 // V_0
IL_000d: br.s IL_000f
I guess that it's a main reason of the slowest execution in comparison with other samples.
The dynamic
object cast
public TEnum DynamicCast()
{
return (TEnum) (dynamic) 0;
}
looks more complicated
IL_0001: ldsfld class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>> TestConsoleApp.Test/'<>o__0'::'<>p__0'
IL_0006: brfalse.s IL_000a
IL_0008: br.s IL_002f
IL_000a: ldc.i4.s 16 // 0x10
IL_000c: ldtoken TestConsoleApp.Test/TEnum
IL_0011: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0016: ldtoken TestConsoleApp.Test
IL_001b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0020: call class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::Convert(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, class [System.Runtime]System.Type, class [System.Runtime]System.Type)
IL_0025: call class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<!0/*class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>*/> class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>>::Create(class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSiteBinder)
IL_002a: stsfld class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>> TestConsoleApp.Test/'<>o__0'::'<>p__0'
IL_002f: ldsfld class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>> TestConsoleApp.Test/'<>o__0'::'<>p__0'
IL_0034: ldfld !0/*class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>*/ class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>>::Target
IL_0039: ldsfld class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite`1<class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>> TestConsoleApp.Test/'<>o__0'::'<>p__0'
IL_003e: ldc.i4.0
IL_003f: box [System.Runtime]System.Int32
IL_0044: callvirt instance !2/*valuetype TestConsoleApp.Test/TEnum*/ class [System.Runtime]System.Func`3<class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite, object, valuetype TestConsoleApp.Test/TEnum>::Invoke(!0/*class [System.Linq.Expressions]System.Runtime.CompilerServices.CallSite*/, !1/*object*/)
IL_0049: stloc.0 // V_0
IL_004a: br.s IL_004c
There is a type information loaded, then instance of CallSiteBinder
is initialized using Binder.Convert
static method. Then an instance of generic CallSite
class is created, using Create
static call (ldsfld
pushes the value of static field into the stack). I'm not 100% sure, but the generic argument Func<CallSite, object, TEnum
means a function, which will be invoked to convert the object into TEnum
. Last lines show that this function is bound to TEnum
class.
So, under the hood compiler already creates you a method to cast a dynamic object to required TEnum
type. And there is only boxing operation from int
to object
to pass it to created function. This sounds like a good reason, why it's faster than object cast with boxing and unboxing operations
Dynamic cast at runtime
No. You can't cast to any type that is unknown at compile time. However, c# does have a special keyword for declaring variables of a type that is unknown - it's dynamic
.
You can think of it like a form of late binding - The actual type of the variable is determind at run time only.
When you declare a dynamic variable, c# compiler actually creates a variable of type object, but does not perform any type checking.
The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time.
...
Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time.
c# dynamic casting or conversion
1)You can iterate over the array
double[] data = new double[] { 1, 2, 3 };
foreach (var item in data)
Console.WriteLine(item.ToString());
2)Or
Console.WriteLine(string.Join(",", data));
The above solutions work if you already have an array of double.
In your case ,if you are sure that data[0] is an array of double you can use the as operator
double[] temp = data[0] as double[];
Console.WriteLine(string.Join(",", temp));
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 does casting from dynamic object works in C#
Your code...
object o = new { Name = "test" };
SampleClass casted = (SampleClass)(dynamic)o; // this won't work
...does not work, not because of the intermediate cast to dynamic
, but because of the type mismatch between your anonymous class and SampleClass
.
Do not confuse dynamic
with anonymous classes. There are no objects of type dynamic
, it is mainly just there for the compiler. On the other hand, anonymous classes are full type-safe classes that exist at compile time. There is no difference to non-anonymous classes, except that you don't know the name. The compiler will create a full class definition under the hood (check with a decompiler).
This is also the problem with your assignment. You are tryig to assign an object of your anonymous class to a variable of type SampleClass
. This can not work (and it doesn't matter that they share the Name
property). You can just as well try to assign a string
, int
or any other type (except SampleClass
), the result will be exactly the same.
Always keep in mind that C# is strongly typed. In weakly typed languages like JavaScript, your assignment would work. Not so in C#.
UPDATE (with information from the question's comments):
Your assignment...
SalesOrder readOrder = (SalesOrder)(dynamic)response.Resource;
...is different in an important aspect. The converted type implements the IDynamicMetaObjectProvider
interface. The cast to dynamic
makes the compiler recognize this interface. It can then inject code to do a conversion to SalesOrder
using that interface. It will result in completely different code that will perform a dynamic runtime conversion of the source object that has nothing to do with a regular typecast.
Related Topics
Differencebetween a Property and a Variable
How to Read Data from a Zip File Without Having to Unzip the Entire File
Find Index of a Value in an Array
What Is an MVChtmlstring and When Should I Use It
How to Check If Tcpclient Connection Is Closed
Is There Anything Like Asynchronous Blockingcollection<T>
How to Add Claims in ASP.NET Identity
How to Add an Extra Button to the Window's Title Bar
One to One Optional Relationship Using Entity Framework Fluent API
How to Copy Part of an Array to Another Array in C#
Deleting Specific Rows from Datatable
Signing and Verifying Signatures with Rsa C#
Double Buffering When Not Drawing in Onpaint(): Why Doesn't It Work
Just What Is an Intptr Exactly
"Updatesourcetrigger=Propertychanged" Equivalent for a Windows Phone 7 Textbox