public object ToStruct(Type structType) { Throw.If(Type != VMType.Struct, "not a valid source struct"); Throw.If(!structType.IsStructOrClass(), "not a valid destination struct"); var dict = this.GetChildren(); var fields = structType.GetFields(); var result = Activator.CreateInstance(structType); object boxed = result; foreach (var field in fields) { var key = VMObject.FromObject(field.Name); Throw.If(!dict.ContainsKey(key), "field not present in source struct: " + field.Name); var val = dict[key].ToObject(field.FieldType); // here we check if the types mismatch // in case of getting a byte[] instead of an object, we try unserializing the bytes in a different approach // NOTE this should not be necessary often, but is already getting into black magic territory... if (val != null && field.FieldType != typeof(byte[]) && val.GetType() == typeof(byte[])) { if (typeof(ISerializable).IsAssignableFrom(field.FieldType)) { var temp = (ISerializable)Activator.CreateInstance(field.FieldType); var bytes = (byte[])val; using (var stream = new MemoryStream(bytes)) { using (var reader = new BinaryReader(stream)) { temp.UnserializeData(reader); } } val = temp; } } // HACK allows treating uints as enums, without this it is impossible to transform between C# objects and VM objects if (field.FieldType.IsEnum && !val.GetType().IsEnum) { val = Enum.Parse(field.FieldType, val.ToString()); } field.SetValue(boxed, val); } return(boxed); }
public object ToStruct(Type structType) { Throw.If(Type != VMType.Struct, "not a valid source struct"); Throw.If(!structType.IsStructOrClass(), "not a valid destination struct"); var dict = this.GetChildren(); var fields = structType.GetFields(); var result = Activator.CreateInstance(structType); object boxed = result; foreach (var field in fields) { var key = VMObject.FromObject(field.Name); Throw.If(!dict.ContainsKey(key), "field not present in source struct: " + field.Name); var val = dict[key].ToObject(field.FieldType); field.SetValue(boxed, val); } return(boxed); }
// this does the opposite of ToStruct(), takes a InteropObject and converts it to a VM.Struct private static VMObject CastViaReflection(object srcObj, int level) { var srcType = srcObj.GetType(); if (srcType.IsArray) { var children = new Dictionary <VMObject, VMObject>(); var array = (Array)srcObj; for (int i = 0; i < array.Length; i++) { var val = array.GetValue(i); var key = new VMObject(); key.SetValue(i); var vmVal = CastViaReflection(val, level + 1); children[key] = vmVal; } var result = new VMObject(); result.SetValue(children); return(result); } else { var targetType = VMObject.GetVMType(srcType); VMObject result; bool isKnownType = typeof(BigInteger) == srcType || typeof(Timestamp) == srcType || typeof(ISerializable).IsAssignableFrom(srcType); if (srcType.IsStructOrClass() && !isKnownType) { var children = new Dictionary <VMObject, VMObject>(); var fields = srcType.GetFields(); if (fields.Length > 0) { foreach (var field in fields) { var key = new VMObject(); key.SetValue(field.Name); var val = field.GetValue(srcObj); var vmVal = CastViaReflection(val, level + 1); children[key] = vmVal; } result = new VMObject(); result.SetValue(children); return(result); } } result = VMObject.FromObject(srcObj); if (result != null) { return(result); } throw new Exception($"invalid cast: Interop.{srcType.Name} to vm object"); } }
// this does the opposite of ToStruct(), takes a InteropObject and converts it to a VM.Struct private static VMObject CastViaReflection(object srcObj, int level) { var srcType = srcObj.GetType(); if (srcType.IsArray) { var children = new Dictionary <VMObject, VMObject>(); var array = (Array)srcObj; for (int i = 0; i < array.Length; i++) { var val = array.GetValue(i); var key = new VMObject(); key.SetValue(i); var vmVal = CastViaReflection(val, level + 1); children[key] = vmVal; } var result = new VMObject(); result.SetValue(children); return(result); } else { VMObject result; if (level == 0 && srcType.IsStructOrClass()) { var children = new Dictionary <VMObject, VMObject>(); var fields = srcType.GetFields(); if (fields.Length > 0) { foreach (var field in fields) { var key = new VMObject(); key.SetValue(field.Name); var val = field.GetValue(srcObj); var vmVal = CastViaReflection(val, level + 1); children[key] = vmVal; } result = new VMObject(); result.SetValue(children); return(result); } else { throw new Exception("Invalid cast, no fields available"); } } result = VMObject.FromObject(srcObj); if (result != null) { return(result); } throw new Exception($"invalid cast: Interop.{srcType.Name} to vm object"); } }