- Home /
Dynamic Casting during runtime
So here is a simple problem but I don't know the answer to. I have looked and everyone has said that dynamic casting is impossible but I will give you good people a try.
string aStringVar; object anObjVar;
aStringVar = anObjVar;//this gives a compiler error
Can I change that last line to this:
aStringVar = (aStringVar.GetType())anObjVar;//still gives me a compiler error!
Is there a way that I can make that cast a dynamic type?
aStringVar = (string)anObjVar;//this will compile, but this isn't what I want
Thanks for your help and your understanding.
You can do it with a generic function I guess - I don't really understand what you are getting at though - do you want to just convert things from one type to another? But you don't know the type in advance?
If that's the case (and it's the only one I can think of) then you need to write a generic method that takes any type (or any type of a certain class etc).
There isn't anyway to cast something dynamically is the answer that I have discovered. Ins$$anonymous$$d I am using Reflection to solve the problem.
Reflection uses objects as parameters, so all I have to do is use PropertyInfo.SetValue(object obj), and that works fine.
Well not in the version in Unity - you'd need a dynamic to do that in .NET - don't believe that it is supported yet.
Answer by whydoidoit · Dec 20, 2013 at 05:33 PM
This is my ReflectionWrapper which you can construct on an instance of an object, a type etc and will let you call public and private methods. I use it mostly to wrap things that aren't supposed to be exposed by Unity.
It can do things like setting/getting a sub property whatever. It's got generics to cast the type more easily:
var wrapper = new ReflectionWrapper(someObject);
int i = wrapper.GetValue<int>("somePropertyOrField");
string j = wrapper.GetValue<string>("someObjectFieldOrProperty.someStringProperty");
wrapper.SetValue("someOtherObjectFieldOrProperty.someString", j);
wrapper.Call("SomeMethod");
int = wrapper.Call<int>("SomeFunction");
You can also wrap an object by just knowing its type name and assembly then call ConstructInstance:
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections;
using System;
using System.Reflection;
using System.Linq;
public class ReflectionWrapper
{
public Type baseType;
public object instance;
public ReflectionWrapper(string assemblyName, string typeName)
{
var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a=> { return a.GetName().Name == assemblyName; });
baseType = assembly.GetType (assemblyName + "." + typeName);
if(baseType == null)
baseType = assembly.GetType (typeName);
}//
public ReflectionWrapper(Assembly assembly, string typeName)
{
baseType = assembly.GetType (typeName);
}
public ReflectionWrapper(object instance)
{
baseType = instance.GetType();
this.instance = instance;
}
public object this[string path]
{
get
{
return GetValue(path);
}
set
{
SetValue (path, value);
}
}
public object GetValue (string path)
{
var pathParts = path.Split('.');
var currentObject = instance;//
for(var i = 0; i < pathParts.Length; i++)
{
var f = currentObject.GetType().GetField(pathParts[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if(f != null)
{
currentObject = f.GetValue(currentObject);
}
else
{
var p = currentObject.GetType().GetProperty(pathParts[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if(p == null)
throw new Exception("Property not found: " + pathParts[i]);
currentObject = p.GetValue(currentObject, null);
}
}
return currentObject;
}
public void SetValue (string path, object value)
{
var pathParts = path.Split('.');
var currentObject = instance;//
for(var i = 0; i < pathParts.Length-1; i++)
{
var f = currentObject.GetType().GetField(pathParts[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if(f != null)
{
currentObject = f.GetValue(currentObject);
}
else
{
var p = currentObject.GetType().GetProperty(pathParts[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if(p == null)
throw new Exception("Property not found: " + pathParts[i]);
currentObject = p.GetValue(currentObject, null);
}
}
//Set the last part
{
var f = currentObject.GetType().GetField(pathParts[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if(f != null)
{
f.SetValue(currentObject, value);
}
else
{
var p = currentObject.GetType().GetProperty(pathParts[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if(p == null)
throw new Exception("Property not found: " + pathParts[i]);
p.SetValue (currentObject, value, null);
}
}
}
public T GetValue<T>(string path)
{
return (T)GetValue (path);
}
protected void ConstructInstance(Type [] types, params object[] parameters)
{
var constructor = baseType.GetConstructor (types);
instance = constructor.Invoke (parameters);
}
protected void ConstructInstance(params object[] parameters)
{
var constructor = baseType.GetConstructor (parameters.Select (p => p.GetType ()).ToArray ());
instance = constructor.Invoke (parameters);
}
public T GetProperty<T>(string name)
{
return (T)GetProperty (name);
}
public T GetField<T>(string name)
{
return (T)GetField (name);
}
public T Call<T>(string name, params object[] parameters)
{
return (T)Call (name, parameters) ;
}
public object GetProperty(string name)
{
return baseType.GetProperty (name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue (instance, null);
}
public void SetProperty(string name, object value)
{
baseType.GetProperty (name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue (instance, value, null);
}
public object GetField(string name)
{
return baseType.GetField (name, BindingFlags.Public | BindingFlags.NonPublic| BindingFlags.Instance).GetValue (instance);
}
public void SetField(string name, object value)
{
baseType.GetField (name, BindingFlags.Public | BindingFlags.NonPublic| BindingFlags.Instance).SetValue (instance, value);
}
public object Call(string name, params object[] parameters)
{
var method = baseType.GetMethods (
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault (m => {
if(m.Name != name) return false;
var parms = m.GetParameters();//
for(var i = 0; i < parms.Length; i++)
{
if(i >= parameters.Length && !parms[i].IsOptional)
return false;
if(i < parameters.Length && !parms[i].ParameterType.IsAssignableFrom(parameters[i].GetType()))
return false;
}
return true;
});
return method.Invoke (instance, parameters );
}
public object CallStatic(string name, params object[] parameters)
{
var method = baseType.GetMethods (
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.FirstOrDefault (m => {
if(m.Name != name) return false;
var parms = m.GetParameters();//
for(var i = 0; i < parms.Length; i++)
{
if(i >= parameters.Length && !parms[i].IsOptional)
return false;
if(i < parameters.Length && !parms[i].ParameterType.IsAssignableFrom(parameters[i].GetType()))
return false;
}
return true;
});
return method.Invoke (null, parameters );
}
public void SetDelegate(string name, Delegate del)
{
var field = baseType.GetField (
name,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (field != null)
{
field.SetValue (instance, Delegate.CreateDelegate (field.FieldType, del.Target, del.Method));
}
else
{
var property = baseType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
property.SetValue (instance, Delegate.CreateDelegate (property.PropertyType, del.Target, del.Method), null);
}
}
}
Oh yeah and as a shortcut you can do:
wrapper["Something.SomethingElse"] = 1;
object o = wrapper["SomeProperty"];
BTW the reason ConstructInstance is protected is that in the case that you are making these things I sub class RefectionWrapper to make a nice interface to it and to encapsulate the necessary constructor parameters.
Your answer
Follow this Question
Related Questions
Problem with type casting from C# to JS 3 Answers
Cannot cast from source type to destination type 0 Answers
How do I cast an IntPtr to another class? 0 Answers
Converting to ColliderCast - what's included in the PhysicsWorld and how do I include my own meshes? 0 Answers
Error, class project 1 Answer