private static void ResolveRefs(object original, object root, string currentPath) { if (original is SpeckleAbstract) { SpeckleAbstract myObj = ( SpeckleAbstract )original; if (myObj._type == "ref") { Converter.LinkRef(root, myObj._ref, currentPath); } else { foreach (var key in myObj.Properties.Keys) { Converter.ResolveRefs(myObj.Properties[key], root, currentPath + "/" + key); } } } if (original is IDictionary) { foreach (DictionaryEntry kvp in ( IDictionary )original) { Converter.ResolveRefs(kvp.Value, root, currentPath + "/{" + kvp.Key.ToString() + "}"); } } if (original is List <object> ) { List <object> myList = (List <object>)original; int index = 0; foreach (object obj in myList) { Converter.ResolveRefs(obj, root, currentPath + "/[" + index++ + "]"); } } }
private static object ShallowConvert(SpeckleAbstract obj) { var keys = obj.Properties.Keys; var newDict = new Dictionary <string, object>(); foreach (string key in keys) { newDict.Add(key, Converter.ReadValue(obj.Properties[key], obj)); } obj.Properties = newDict; return(obj); }
/// <summary> /// Serialises an object to a speckle object. /// </summary> /// <param name="source">The object you want to serialise.</param> /// <param name="recursionDepth">Leave this blank, unless you really know what you're doing.</param> /// <param name="traversed">Leave this blank, unless you really know what you're doing.</param> /// <param name="path">Leave this blank, unless you really know what you're doing.</param> /// <returns></returns> public static SpeckleObject Serialise(object source, int recursionDepth = 0, Dictionary <int, string> traversed = null, string path = "") { // null check if (source == null) { return(new SpeckleNull()); } // init optional parameters if (traversed == null) { traversed = new Dictionary <int, string>(); } if (path == "") { path = "root"; } // check references if (traversed.ContainsKey(source.GetHashCode())) { return new SpeckleAbstract() { _type = "ref", _ref = traversed[source.GetHashCode()] } } ; else { traversed.Add(source.GetHashCode(), path); } // check if it already is a speckle object if (source is SpeckleObject) { return(source as SpeckleObject); } // check assemblies if (toSpeckleMethods.ContainsKey(source.GetType().ToString())) { return(toSpeckleMethods[source.GetType().ToString()].Invoke(source, new object[] { source }) as SpeckleObject); } List <Assembly> myAss = System.AppDomain.CurrentDomain.GetAssemblies().ToList().FindAll(s => s.FullName.Contains("Speckle") && s.FullName.Contains("Converter")); List <MethodInfo> methods = new List <MethodInfo>(); foreach (var ass in myAss) { methods.AddRange(Converter.GetExtensionMethods(ass, source.GetType(), "ToSpeckle")); } // if we have a "ToSpeckle" extension method, then invoke that and return its result if (methods.Count > 0) { try { var obj = methods[0].Invoke(source, new object[] { source }); return(obj as SpeckleObject); } catch { return(new SpeckleNull()); } } // else just continue with the to abstract part SpeckleAbstract result = new SpeckleAbstract(); result._type = source.GetType().Name; result._assembly = source.GetType().Assembly.FullName; Dictionary <string, object> dict = new Dictionary <string, object>(); var properties = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var prop in properties) { if (!prop.CanWrite) { continue; } try { var value = prop.GetValue(source); if (value == null) { continue; } dict[prop.Name] = WriteValue(value, recursionDepth, traversed, path + "/" + prop.Name); } catch { } } var fields = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (var field in fields) { if (field.IsNotSerialized) { continue; } try { var value = field.GetValue(source); if (value == null) { continue; } dict[field.Name] = WriteValue(value, recursionDepth, traversed, path + "/" + field.Name); } catch { } } result.Properties = dict; result.Hash = result.GeometryHash = result.GetMd5FromObject(result.Properties); return(result); }
/// <summary> /// Deserialises a speckle object. /// </summary> /// <param name="obj"></param> /// <returns>an object, a SpeckleAbstract or null.</returns> public static object Deserialise(SpeckleObject obj, object root = null) { try { // null check if (obj == null) { return(null); } // if it's not a speckle abstract object if (!(obj is SpeckleAbstract)) { // assembly check var type = obj.GetType().ToString(); if (toNativeMethods.ContainsKey(type)) { return(toNativeMethods[obj.GetType().ToString()].Invoke(obj, new object[] { obj })); } List <Assembly> myAss = System.AppDomain.CurrentDomain.GetAssemblies().ToList().FindAll(s => s.FullName.Contains("Speckle") && s.FullName.Contains("Converter")); List <MethodInfo> methods = new List <MethodInfo>(); foreach (var ass in myAss) { methods.AddRange(Converter.GetExtensionMethods(ass, obj.GetType(), "ToNative")); } // if we have some ToNative method if (methods.Count > 0) { toNativeMethods.Add(type, methods[0]); var result = methods[0].Invoke(obj, new object[] { obj }); if (result != null) { return(result); } } // otherwise return null return(null); } else { // we have a speckle abstract object SpeckleAbstract absObj = obj as SpeckleAbstract; if (absObj._type == "ref") { return(null); } //var shortName = absObj._assembly.Split( ',' )[ 0 ]; var assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == absObj._assembly); //try again if (assembly == null) { var shortName = absObj._assembly.Split(',')[0]; assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.Contains(shortName)); } if (assembly == null) // we can't deserialise for sure { return(Converter.ShallowConvert(absObj)); } var type = assembly.GetTypes().FirstOrDefault(t => t.Name == absObj._type); if (type == null) // type not present in the assembly { return(Converter.ShallowConvert(absObj)); } object myObject = null; try { var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null); if (constructor != null) { myObject = constructor.Invoke(new object[] { }); } if (myObject == null) { myObject = Activator.CreateInstance(type); } } catch { myObject = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); } if (myObject == null) { return(null); } if (root == null) { root = myObject; } var keys = absObj.Properties.Keys; foreach (string key in keys) { var prop = TryGetProperty(type, key); var field = type.GetField(key); if (prop == null && field == null) { continue; } if (absObj.Properties[key] == null) { continue; } var value = ReadValue(absObj.Properties[key], root); // handles both hashsets and lists or whatevers if (value is IEnumerable && !(value is IDictionary) && value.GetType() != typeof(string)) { try { if ((prop != null && prop.PropertyType.IsArray) || (field != null && field.FieldType.IsArray)) { value = ((List <object>)value).ToArray(); } else { var mySubList = Activator.CreateInstance(prop != null ? prop.PropertyType : field.FieldType); foreach (var myObj in ((IEnumerable <object>)value)) { mySubList.GetType().GetMethod("Add").Invoke(mySubList, new object[] { myObj }); } value = mySubList; } } catch { } } // handles dictionaries of all sorts (kind-of!) if (value is IDictionary) { try { var MyDict = Activator.CreateInstance(prop != null ? prop.PropertyType : field.FieldType); foreach (DictionaryEntry kvp in ( IDictionary )value) { MyDict.GetType().GetMethod("Add").Invoke(MyDict, new object[] { Convert.ChangeType(kvp.Key, MyDict.GetType().GetGenericArguments()[0]), kvp.Value }); } value = MyDict; } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); } } // guids are a pain if ((prop != null && prop.PropertyType == typeof(Guid)) || (field != null && field.FieldType == typeof(Guid))) { value = new Guid(( string )value); } // Actually set the value below, whether it's a property or field // if it is a property if (prop != null && prop.CanWrite) { if (prop.PropertyType.IsEnum) { prop.SetValue(myObject, Enum.ToObject(prop.PropertyType, Convert.ChangeType(value, TypeCode.Int32))); } else { try { prop.SetValue(myObject, value); } catch { try { prop.SetValue(myObject, Convert.ChangeType(value, prop.PropertyType)); } catch { } } } } // if it is a field else if (field != null) { if (field.FieldType.IsEnum) { field.SetValue(myObject, Enum.ToObject(field.FieldType, Convert.ChangeType(value, TypeCode.Int32))); } else { try { field.SetValue(absObj, value); } catch { try { field.SetValue(myObject, Convert.ChangeType(value, field.FieldType)); } catch { } } } } } // set references too. if (root == myObject) { Converter.ResolveRefs(absObj, myObject, "root"); } return(myObject); } } catch { return(null); } }
/// <summary> /// Serialises an object to a speckle object. /// </summary> /// <param name="source">The object you want to serialise.</param> /// <param name="recursionDepth">Leave this blank, unless you really know what you're doing.</param> /// <param name="traversed">Leave this blank, unless you really know what you're doing.</param> /// <param name="path">Leave this blank, unless you really know what you're doing.</param> /// <param name="excludeAssebmlies">List of speckle kits assembly names to exclude from the search.</param> /// <returns></returns> public static SpeckleObject Serialise(object source, int recursionDepth = 0, Dictionary <int, string> traversed = null, string path = "", IEnumerable <string> excludeAssebmlies = null) { if (source == null) { return(new SpeckleNull()); } //if ( source is IEnumerable ) return Converter.Serialise( source as IEnumerable<object> ); if (traversed == null) { traversed = new Dictionary <int, string>(); } if (path == "") { path = "root"; } // check references if (traversed.ContainsKey(source.GetHashCode())) { return new SpeckleAbstract() { _type = "ref", _ref = traversed[source.GetHashCode()] } } ; else { traversed.Add(source.GetHashCode(), path); } // check if it already is a speckle object if (source is SpeckleObject) { return(source as SpeckleObject); } // check assemblies if (toSpeckleMethods.ContainsKey(source.GetType().ToString())) { return(toSpeckleMethods[source.GetType().ToString()].Invoke(source, new object[] { source }) as SpeckleObject); } var methods = new List <MethodInfo>(); foreach (var ass in SpeckleCore.SpeckleInitializer.GetAssemblies().Where(ass => (excludeAssebmlies != null ? !excludeAssebmlies.Contains(ass.FullName) : true))) { try { methods.AddRange(Converter.GetExtensionMethods(ass, source.GetType(), "ToSpeckle")); } catch { } // handling errors thrown when we're attempting to load something with missing references (ie, dynamo stuff in rhino, or vice-versa). } // if we have a "ToSpeckle" extension method, then invoke that and return its result if (methods.Count > 0) { try { var obj = methods[0].Invoke(source, new object[] { source }); if (obj != null) { toSpeckleMethods.Add(source.GetType().ToString(), methods[0]); return(obj as SpeckleObject); } else { return(new SpeckleNull()); } } catch { return(new SpeckleNull()); } } // else just continue with the to abstract part SpeckleAbstract result = new SpeckleAbstract(); result._type = source.GetType().Name; result._assembly = source.GetType().Assembly.FullName; Dictionary <string, object> dict = new Dictionary <string, object>(); var properties = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var prop in properties) { if (!prop.CanWrite) { continue; } try { var value = prop.GetValue(source); if (value == null) { continue; } dict[prop.Name] = WriteValue(value, recursionDepth, traversed, path + "/" + prop.Name); } catch { } } var fields = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (var field in fields) { if (field.IsNotSerialized) { continue; } try { var value = field.GetValue(source); if (value == null) { continue; } dict[field.Name] = WriteValue(value, recursionDepth, traversed, path + "/" + field.Name); } catch { } } result.Properties = dict; result.Hash = result.GeometryHash = result.GetMd5FromObject(result.Properties); return(result); }
/// <summary> /// Serialises an object to a speckle object. /// </summary> /// <param name="source">The object you want to serialise.</param> /// <param name="recursionDepth">Leave this blank, unless you really know what you're doing.</param> /// <param name="traversed">Leave this blank, unless you really know what you're doing.</param> /// <param name="path">Leave this blank, unless you really know what you're doing.</param> /// <param name="excludeAssebmlies">List of speckle kits assembly names to exclude from the search.</param> /// <returns></returns> public static object Serialise(object source, int recursionDepth = 0, Dictionary <int, string> traversed = null, string path = "", IEnumerable <string> excludeAssebmlies = null) { if (source == null) { return(new SpeckleNull()); } //if ( source is IEnumerable ) return Converter.Serialise( source as IEnumerable<object> ); if (traversed == null) { traversed = new Dictionary <int, string>(); } if (path == "") { path = "root"; } // check references if (traversed.ContainsKey(source.GetHashCode())) { return new SpeckleAbstract() { _type = "ref", _ref = traversed[source.GetHashCode()] } } ; else { traversed.Add(source.GetHashCode(), path); } // check if it already is a speckle object if (source is SpeckleObject) { return(source as SpeckleObject); } // check assemblies if (toSpeckleMethods.ContainsKey(source.GetType().ToString())) { return(toSpeckleMethods[source.GetType().ToString()].Invoke(source, new object[] { source })); } var methods = new List <MethodInfo>(); var currentType = source.GetType(); var baseTypes = new List <Type>(); // create a list of base types while (currentType != null) { baseTypes.Add(currentType); currentType = currentType.BaseType; } // populate the ToSpeckle method array foreach (var ass in SpeckleCore.SpeckleInitializer.GetAssemblies().Where(ass => (excludeAssebmlies != null ? !excludeAssebmlies.Contains(ass.FullName) : true))) { foreach (var type in baseTypes) { try { methods.AddRange(Converter.GetExtensionMethods(ass, type, "ToSpeckle")); } catch { } } } // iterate through the ToSpeckle method array if (methods.Count > 0) { foreach (var method in methods) { try { var obj = method.Invoke(source, new object[] { source }); if (obj != null) { toSpeckleMethods.Add(source.GetType().ToString(), method); return(obj); } } catch { return(new SpeckleNull()); } } } // if we haven't returned anything by this point, we should go abstract SpeckleAbstract result = new SpeckleAbstract(); result._type = source.GetType().Name; result._assembly = source.GetType().Assembly.FullName; Dictionary <string, object> dict = new Dictionary <string, object>(); var properties = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var prop in properties) { if (!prop.CanWrite) { continue; } try { var value = prop.GetValue(source); if (value == null) { continue; } dict[prop.Name] = WriteValue(value, recursionDepth, traversed, path + "/" + prop.Name); } catch { } } var fields = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (var field in fields) { if (field.IsNotSerialized) { continue; } try { var value = field.GetValue(source); if (value == null) { continue; } dict[field.Name] = WriteValue(value, recursionDepth, traversed, path + "/" + field.Name); } catch { } } result.Properties = dict; result.Hash = result.GeometryHash = result.GetMd5FromObject(result.GetMd5FromObject(result._assembly) + result.GetMd5FromObject(result._type) + result.GetMd5FromObject(result.Properties)); return(result); }