using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
using System.Text;
using System.Xml;
{
var l = new List<TypeMapMember> ();
foreach (var fi in type.GetFields ())
- l.Add (new TypeMapField (fi, null));
+ if (!fi.IsStatic)
+ l.Add (new TypeMapField (fi, null));
foreach (var pi in type.GetProperties ())
- if (pi.CanRead && pi.CanWrite)
+ if (pi.CanRead && pi.CanWrite && !pi.GetGetMethod (true).IsStatic && pi.GetIndexParameters ().Length == 0)
l.Add (new TypeMapProperty (pi, null));
+ l.Sort ((x, y) => x.Order != y.Order ? x.Order - y.Order : String.Compare (x.Name, y.Name, StringComparison.Ordinal));
return new TypeMap (type, null, l.ToArray ());
}
- static bool IsCollection (Type type)
+ internal static bool IsDictionary (Type type)
{
- if (type.GetInterface ("System.Collections.IList") != null)
+ Type inter;
+ inter = type.GetInterface ("System.Collections.IDictionary", false);
+ if (inter != null
+ && type.GetMethod ("Add", new Type[] { typeof (object), typeof (object) }) != null)
return true;
- if (type.GetInterface ("System.Collections.Generic.IList`1") != null)
+
+ inter = type.GetInterface ("System.Collections.Generic.IDictionary`2", false);
+ if (inter != null
+ && type.GetMethod ("Add", new Type[] { inter.GetGenericArguments() [0],
+ inter.GetGenericArguments() [1] }) != null)
return true;
- if (type.GetInterface ("System.Collections.Generic.ICollection`1") != null)
+ return false;
+ }
+
+ internal static bool IsEnumerable (Type type)
+ {
+ if (type.IsGenericType &&
+ type.GetGenericTypeDefinition() == typeof (LinkedList<>))
+ return true;
+
+ if (IsPrimitiveType (type) || IsDictionary (type))
+ return false;
+
+ Type inter;
+ inter = type.GetInterface ("System.Collections.Generic.IReadOnlyCollection`1", false);
+ if (inter != null)
+ return true;
+
+ inter = type.GetInterface ("System.Collections.IEnumerable", false);
+ if (inter != null && type.GetMethod ("Add", new Type[] { typeof (object) }) != null)
+ return true;
+
+ inter = type.GetInterface ("System.Collections.Generic.IEnumerable`1", false);
+ if (inter != null && type.GetMethod ("Add", new Type[] { inter.GetGenericArguments() [0] }) != null)
return true;
return false;
}
List<TypeMapMember> members = new List<TypeMapMember> ();
- foreach (FieldInfo fi in type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+ foreach (FieldInfo fi in type.GetFields (binding_flags)) {
+ if (fi.GetCustomAttributes (typeof (CompilerGeneratedAttribute), false).Length > 0)
+ continue;
if (dca != null) {
object [] atts = fi.GetCustomAttributes (typeof (DataMemberAttribute), true);
if (atts.Length == 0)
DataMemberAttribute dma = (DataMemberAttribute) atts [0];
members.Add (new TypeMapField (fi, dma));
} else {
- if (fi.GetCustomAttributes (typeof (NonSerializedAttribute), false).Length > 0)
+ if (fi.GetCustomAttributes (typeof (IgnoreDataMemberAttribute), false).Length > 0)
continue;
members.Add (new TypeMapField (fi, null));
}
}
if (dca != null) {
- foreach (PropertyInfo pi in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
- continue;
+ foreach (PropertyInfo pi in type.GetProperties (binding_flags)) {
object [] atts = pi.GetCustomAttributes (typeof (DataMemberAttribute), true);
if (atts.Length == 0)
continue;
if (pi.GetIndexParameters ().Length > 0)
- if (IsCollection (pi.PropertyType)) {
+ continue;
+ if (IsEnumerable (pi.PropertyType) || IsDictionary (pi.PropertyType)) {
if (!pi.CanRead)
throw new InvalidDataContractException (String.Format ("Property {0} must have a getter", pi));
}
}
}
- members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order - m2.Order; });
+ members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order != m2.Order ? m1.Order - m2.Order : String.CompareOrdinal (m1.Name, m2.Name); });
return new TypeMap (type, dca == null ? null : dca.Name, members.ToArray ());
}
string element;
TypeMapMember [] members;
+ static readonly Type [] deser_methods_args = new Type [] { typeof (StreamingContext) };
+ const BindingFlags binding_flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+
public TypeMap (Type type, string element, TypeMapMember [] orderedMembers)
{
this.type = type;
this.element = element;
this.members = orderedMembers;
+
+ foreach (var mi in type.GetMethods (binding_flags)) {
+ if (mi.GetCustomAttributes (typeof (OnDeserializingAttribute), false).Length > 0)
+ OnDeserializing = mi;
+ else if (mi.GetCustomAttributes (typeof (OnDeserializedAttribute), false).Length > 0)
+ OnDeserialized = mi;
+ else if (mi.GetCustomAttributes (typeof (OnSerializingAttribute), false).Length > 0)
+ OnSerializing = mi;
+ else if (mi.GetCustomAttributes (typeof (OnSerializedAttribute), false).Length > 0)
+ OnSerialized = mi;
+ }
}
- public void Serialize (JsonSerializationWriter outputter, object graph)
+ public MethodInfo OnDeserializing { get; set; }
+ public MethodInfo OnDeserialized { get; set; }
+ public MethodInfo OnSerializing { get; set; }
+ public MethodInfo OnSerialized { get; set; }
+
+ public virtual void Serialize (JsonSerializationWriter outputter, object graph, string type)
{
+ if (OnSerializing != null)
+ OnSerializing.Invoke (graph, new object [] {new StreamingContext (StreamingContextStates.All)});
+
+ outputter.Writer.WriteAttributeString ("type", type);
foreach (TypeMapMember member in members) {
object memberObj = member.GetMemberOf (graph);
// FIXME: consider EmitDefaultValue
outputter.WriteObjectContent (memberObj, false, false);
outputter.Writer.WriteEndElement ();
}
+
+ if (OnSerialized != null)
+ OnSerialized.Invoke (graph, new object [] {new StreamingContext (StreamingContextStates.All)});
+ }
+
+ internal static object CreateInstance (Type type)
+ {
+ if (TypeMap.IsDictionary (type)) {
+ if (type.IsGenericType)
+ return Activator.CreateInstance (typeof (Dictionary<,>).MakeGenericType (type.GetGenericArguments ()));
+ else
+ return new Hashtable ();
+ } else if (TypeMap.IsEnumerable (type)) {
+ if (type.IsGenericType)
+ return Activator.CreateInstance (typeof (List<>).MakeGenericType (type.GetGenericArguments ()));
+ else
+ return new ArrayList ();
+ }
+ else
+ return FormatterServices.GetUninitializedObject (type);
}
- public object Deserialize (JsonSerializationReader jsr)
+ public virtual object Deserialize (JsonSerializationReader jsr, object o)
{
XmlReader reader = jsr.Reader;
-#if NET_2_1
- // should it reject non-public constructor?
- object ret = Activator.CreateInstance (type);
-#else
- object ret = Activator.CreateInstance (type, true);
-#endif
+ bool isNull = reader.GetAttribute ("type") == "null";
+
+ object ret = isNull ? null : CreateInstance (type);
+ if (ret != null && OnDeserializing != null)
+ OnDeserializing.Invoke (ret, new object [] {new StreamingContext (StreamingContextStates.All)});
Dictionary<TypeMapMember,bool> filled = new Dictionary<TypeMapMember,bool> ();
reader.ReadStartElement ();
if (mm.Name == reader.LocalName && reader.NamespaceURI == String.Empty) {
if (filled.ContainsKey (mm))
throw new SerializationException (String.Format ("Object content '{0}' for '{1}' already appeared in the reader", reader.LocalName, type));
- mm.SetMemberValue (ret, jsr.ReadObject (mm.Type));
+ mm.SetMemberValue (ret, jsr);
filled [mm] = true;
consumed = true;
break;
reader.Skip ();
}
reader.ReadEndElement ();
+ if (ret != null && OnDeserialized != null)
+ OnDeserialized.Invoke (ret, new object [] {new StreamingContext (StreamingContextStates.All)});
return ret;
}
}
get { return dma == null ? mi.Name : dma.Name ?? mi.Name; }
}
- // FIXME: Fill 3.5 member in s.r.serialization.
-// public bool EmitDefaultValue {
-// get { return dma != null && dma.EmitDefaultValue; }
-// }
+ public bool EmitDefaultValue {
+ get { return dma != null && dma.EmitDefaultValue; }
+ }
public bool IsRequired {
get { return dma != null && dma.IsRequired; }
public abstract object GetMemberOf (object owner);
- public abstract void SetMemberValue (object owner, object value);
+ public abstract void SetMemberValue (object owner, JsonSerializationReader value);
}
class TypeMapField : TypeMapMember
{
return field.GetValue (owner);
}
-
- public override void SetMemberValue (object owner, object value)
+
+ public override void SetMemberValue (object owner, JsonSerializationReader jsr)
{
- field.SetValue (owner, value);
+ field.SetValue (owner, jsr.ReadObject (this.Type));
}
}
return property.GetValue (owner, null);
}
- public override void SetMemberValue (object owner, object value)
+ public override void SetMemberValue (object owner, JsonSerializationReader jsr)
{
- property.SetValue (owner, value, null);
+ var pSetter = this.property.GetSetMethod (true);
+ if (pSetter != null) {
+ property.SetValue (owner, jsr.ReadObject (this.Type), null);
+
+ } else { // no setter
+ var oldValue = property.GetValue (owner, null);
+ try {
+ jsr.ReadObject (this.Type, oldValue);
+ } catch (MissingMethodException e) {
+ throw new InvalidDataContractException (string.Format ("No set method for property '{0}' "
+ + "in type '{1}'.", this.property.Name, this.property.PropertyType.FullName), e);
+ }
+ }
}
}
}