C#: Dynamic runtime cast
I realize this has been answered, but I used a different approach and thought it might be worth sharing. Also, I feel like my approach might produce unwanted overhead. However, I'm not able to observer or calculate anything happening that is that bad under the loads we observe. I was looking for any useful feedback on this approach.
The problem with working with dynamics is that you can't attach any functions to the dynamic object directly. You have to use something that can figure out the assignments that you don't want to figure out every time.
When planning this simple solution, I looked at what the valid intermediaries are when attempting to retype similar objects. I found that a binary array, string (xml, json) or hard coding a conversion (IConvertable) were the usual approaches. I don't want to get into binary conversions due to a code maintainability factor and laziness.
My theory was that Newtonsoft could do this by using a string intermediary.
As a downside, I am fairly certain that when converting the string to an object, that it would use reflection by searching the current assembly for an object with matching properties, create the type, then instantiate the properties, which would require more reflection. If true, all of this can be considered avoidable overhead.
C#:
//This lives in a helper class
public static ConvertDynamic<T>(dynamic data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Newtonsoft.Json.JsonConvert.SerializeObject(data));
}
//Same helper, but in an extension class (public static class),
//but could be in a base class also.
public static ToModelList<T>(this List<dynamic> list)
{
List<T> retList = new List<T>();
foreach(dynamic d in list)
{
retList.Add(ConvertDynamic<T>(d));
}
}
With that said, this fits another utility I've put together that lets me make any object into a dynamic. I know I had to use reflection to do that correctly:
public static dynamic ToDynamic(this object value)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
return expando as ExpandoObject;
}
I had to offer that function. An arbitrary object assigned to a dynamic typed variable cannot be converted to an IDictionary, and will break the ConvertDynamic function. For this function chain to be used it has to be provided a dynamic of System.Dynamic.ExpandoObject, or IDictionary<string, object>.
This should work:
public static dynamic Cast(dynamic obj, Type castTo)
{
return Convert.ChangeType(obj, castTo);
}
Edit
I've written the following test code:
var x = "123";
var y = Cast(x, typeof(int));
var z = y + 7;
var w = Cast(z, typeof(string)); // w == "130"
It does resemble the kind of "typecasting" one finds in languages like PHP, JavaScript or Python (because it also converts the value to the desired type). I don't know if that's a good thing, but it certainly works... :-)
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.