private bool WriteSpecialObject(object o) { // if the object here is value type, it is in fact boxed // value type - the reference layout is fine, we should // write it using WriteField var type = o.GetType(); if(type.IsValueType) { WriteField(type, o); return true; } var speciallySerializable = o as ISpeciallySerializable; if(speciallySerializable != null) { var startingPosition = writer.Position; speciallySerializable.Save(writer); writer.Write(writer.Position - startingPosition); return true; } if(type.IsArray) { var elementType = type.GetElementType(); var array = o as Array; var rank = array.Rank; writer.Write(rank); WriteArray(elementType, array); return true; } var mDelegate = o as MulticastDelegate; if(mDelegate != null) { // if the target is trasient, we omit associated delegate entry var invocationList = GetDelegatesWithNonTransientTargets(mDelegate); writer.Write(invocationList.Length); foreach(var del in invocationList) { WriteField(typeof(object), del.Target); TouchAndWriteMethodId(del.Method); } return true; } var str = o as string; if(str != null) { writer.Write(str); return true; } var collectionToken = new CollectionMetaToken(o.GetType()); if(collectionToken.IsCollection) { // here we can have normal or extension method that needs to be treated differently int count = collectionToken.CountMethod.IsStatic ? (int)collectionToken.CountMethod.Invoke(null, new[] { o }) : (int)collectionToken.CountMethod.Invoke(o, null); if(collectionToken.IsDictionary) { WriteDictionary(collectionToken, count, o); } else { WriteEnumerable(collectionToken.FormalElementType, count, (IEnumerable)o); } return true; } return false; }
private void WriteDictionary(CollectionMetaToken collectionToken, int count, object dictionary) { writer.Write(count); if(collectionToken.IsGeneric) { var enumeratorMethod = typeof(IEnumerable<>).MakeGenericType(typeof(KeyValuePair<,>).MakeGenericType(collectionToken.FormalKeyType, collectionToken.FormalValueType)).GetMethod("GetEnumerator"); var enumerator = enumeratorMethod.Invoke(dictionary, null); var enumeratorType = enumeratorMethod.ReturnType; var moveNext = Helpers.GetMethodInfo<IEnumerator>(x => x.MoveNext()); var currentField = enumeratorType.GetProperty("Current"); var current = currentField.GetGetMethod(); var currentType = current.ReturnType; var key = currentType.GetProperty("Key").GetGetMethod(); var value = currentType.GetProperty("Value").GetGetMethod(); while((bool)moveNext.Invoke(enumerator, null)) { var currentValue = current.Invoke(enumerator, null); var keyValue = key.Invoke(currentValue, null); var valueValue = value.Invoke(currentValue, null); WriteField(collectionToken.FormalKeyType, keyValue); WriteField(collectionToken.FormalValueType, valueValue); } } else { var castDictionary = (IDictionary)dictionary; foreach(DictionaryEntry element in castDictionary) { WriteField(typeof(object), element.Key); WriteField(typeof(object), element.Value); } } }