public static void WalkTypes(List <Type> knownTypes) { Type newType = typeof(T); if (knownTypes.Contains(newType)) { return; } knownTypes.Add(newType); foreach (Property <T> prop in writeProps) { bool dummy; Type propType = prop.PropertyType, actualType = Nullable.GetUnderlyingType(propType) ?? PropertyFactory.GetListType(propType, out dummy) ?? propType; if (Serializer.IsEntityType(actualType)) { typeof(Serializer <>) .MakeGenericType(actualType) .GetMethod("WalkTypes") .Invoke(null, new object[] { knownTypes }); } else if (actualType.IsEnum) { if (!knownTypes.Contains(actualType)) { knownTypes.Add(actualType); } } } }
/// <summary> /// Can the given type be meaningfully with protobuf-net? /// </summary> public static bool CanSerialize(Type type) { if (type == null) { throw new ArgumentNullException("type"); } if (type.IsValueType) { return(false); } // serialize as item? if (Serializer.IsEntityType(type)) { return(true); } // serialize as list? bool enumOnly; Type itemType = PropertyFactory.GetListType(type, out enumOnly); if (itemType != null && (!enumOnly || Serializer.HasAddMethod(type, itemType)) && Serializer.IsEntityType(itemType)) { return(true); } return(false); }
static SerializerProxy() { if (Serializer.IsEntityType(typeof(T))) { Default = (SerializerProxy <T>) typeof(SerializerProxy <T>).GetMethod("MakeItem") .MakeGenericMethod(typeof(T)).Invoke(null, null); } else // see if our property-factory can handle this type; if it can, use a wrapper object { try { DataFormat fmt = DataFormat.Default; if (PropertyFactory.CreatePassThru <T>(1, ref fmt) != null) { Default = (SerializerProxy <T>) typeof(SerializerProxy <T>).GetMethod("MakeValue") .MakeGenericMethod(typeof(T)).Invoke(null, null); } } catch (Exception ex) { Debug.WriteLine(ex.ToString(), "SerializerProxy.cctor"); // nope, can't do it... } } if (Default == null) { throw new InvalidOperationException("Only data-contract classes (and lists/arrays of such) can be processed (error processing " + typeof(T).Name + ")"); } }
private static void BuildCallbacks() { MethodInfo[] methods = typeof(T).GetMethods( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); // protobuf-net specific FindCallback(methods, CallbackType.BeforeSerialization, typeof(ProtoBeforeSerializationAttribute)); FindCallback(methods, CallbackType.AfterSerialization, typeof(ProtoAfterSerializationAttribute)); FindCallback(methods, CallbackType.BeforeDeserialization, typeof(ProtoBeforeDeserializationAttribute)); FindCallback(methods, CallbackType.AfterDeserialization, typeof(ProtoAfterDeserializationAttribute)); #if !SILVERLIGHT && !CF // regular framework FindCallback(methods, CallbackType.BeforeSerialization, typeof(OnSerializingAttribute)); FindCallback(methods, CallbackType.AfterSerialization, typeof(OnSerializedAttribute)); FindCallback(methods, CallbackType.BeforeDeserialization, typeof(OnDeserializingAttribute)); FindCallback(methods, CallbackType.AfterDeserialization, typeof(OnDeserializedAttribute)); #endif Type root = typeof(T).BaseType; bool isRoot = !Serializer.IsEntityType(root); if (!isRoot) { while (Serializer.IsEntityType(root.BaseType)) { root = root.BaseType; } } if (callbacks != null) { if (!isRoot) { throw new ProtoException( "Callbacks are only supported on the root contract type in an inheritance tree; consider implementing callbacks as virtual methods on " + root.FullName); } // otherwise, use BeforeDeserialization for ObjectCreation: callbacks[(int)CallbackType.ObjectCreation] = callbacks[(int)CallbackType.BeforeDeserialization]; } else { methods = root.GetMethods( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); FindCallback(methods, CallbackType.ObjectCreation, typeof(ProtoBeforeDeserializationAttribute)); #if !SILVERLIGHT && !CF FindCallback(methods, CallbackType.ObjectCreation, typeof(OnDeserializingAttribute)); #endif } }
public static SerializerProxy <TItem> MakeItem <TItem>() where TItem : class, T { Type actualType = typeof(TItem), baseType = actualType; while (Serializer.IsEntityType(baseType.BaseType)) { baseType = baseType.BaseType; } if (baseType == actualType) { return(new SerializerItemProxy <TItem, TItem>()); } return((SerializerProxy <TItem>)Activator.CreateInstance( typeof(SerializerItemProxy <,>).MakeGenericType(baseType, actualType))); }
internal static void Build() { if (readProps != null) { return; // completely built and ready for use } #if CF // no wait option on CF if (!Monitor.TryEnter(lockToken)) #else // give it a few seconds on regular .NET if (!Monitor.TryEnter(lockToken, 5000)) #endif { throw new InvalidOperationException("Possible deadlock detected preparing serializer for " + typeof(T).Name + "; try using Serializer.PrepareSerializer to initialize this type at application startup."); } try { if (readProps != null || subclasses != null) { // readProps != null : double-checked locking // readProps == null, but subclasses != null : // this scenario means that we are in the process of building the // serializer; since we hold the lock, this must be re-entrancy, so simply ignore //Trace.WriteLine("Re-entrant short-circuit: " + typeof(T).FullName, "ProtoBuf.Serializer:Build"); return; } //Trace.WriteLine("Building: " + typeof(T).FullName, "ProtoBuf.Serializer:Build"); // otherwise we are building the serializer for the first time; initialize // subclasses as a marker that we are in-progress subclasses = new KeyValuePair <Type, Property <T, T> > [0]; // use this to prevent recursion if (!Serializer.IsEntityType(typeof(T))) { throw new InvalidOperationException("Only data-contract classes can be processed (error processing " + typeof(T).Name + ")"); } BuildCallbacks(); List <Property <T> > readPropList = new List <Property <T> >(), writePropList = new List <Property <T> >(); List <int> tagsInUse = new List <int>(); foreach (MemberInfo prop in Serializer.GetProtoMembers(typeof(T))) { string name; DataFormat format; int tag; MemberSerializationOptions options; if (!Serializer.TryGetTag(prop, out tag, out name, out format, out options)) { continue; // didn't recognise this as a usable property } // check for duplicates if (tagsInUse.Contains(tag)) { throw new InvalidOperationException( string.Format("Duplicate tag {0} detected in {1}", tag, name)); } tagsInUse.Add(tag); Property <T> actualProp = PropertyFactory.Create <T>(prop); writePropList.Add(actualProp); readPropList.Add(actualProp); foreach (Property <T> altProp in actualProp.GetCompatibleReaders()) { if (altProp.Tag != actualProp.Tag) { throw new ProtoException("Alternative readers must handle the same tag"); } foreach (Property <T> tmp in readPropList) { if (tmp.FieldPrefix == altProp.FieldPrefix) { throw new ProtoException("Alternative readers must handle different wire-types"); } } readPropList.Add(altProp); } } #if CF2 CrapSort(readPropList, delegate(Property <T> x, Property <T> y) { return(x.FieldPrefix.CompareTo(y.FieldPrefix)); }); CrapSort(writePropList, delegate(Property <T> x, Property <T> y) { return(x.FieldPrefix.CompareTo(y.FieldPrefix)); }); #else readPropList.Sort(delegate(Property <T> x, Property <T> y) { return(x.FieldPrefix.CompareTo(y.FieldPrefix)); }); writePropList.Sort(delegate(Property <T> x, Property <T> y) { return(x.FieldPrefix.CompareTo(y.FieldPrefix)); }); #endif List <KeyValuePair <Type, Property <T, T> > > subclassList = new List <KeyValuePair <Type, Property <T, T> > >(); foreach (ProtoIncludeAttribute pia in Attribute.GetCustomAttributes(typeof(T), typeof(ProtoIncludeAttribute), false)) { Type subclassType = pia.ResolveKnownType(typeof(T).Assembly); if (subclassType == null) { throw new ProtoException("Unable to identify known-type for ProtoIncludeAttribute: " + pia.KnownTypeName); } if (subclassType.BaseType != typeof(T)) { throw new ProtoException(string.Format( "Known-type {0} for ProtoIncludeAttribute must be a direct subclass of {1}", subclassType.Name, typeof(T).Name)); } Property <T, T> prop; switch (pia.DataFormat) { case DataFormat.Default: prop = (Property <T, T>) PropertyUtil <T> .CreateTypedProperty("CreatePropertyMessageString", typeof(T), typeof(T), subclassType); break; case DataFormat.Group: prop = (Property <T, T>) PropertyUtil <T> .CreateTypedProperty("CreatePropertyMessageGroup", typeof(T), typeof(T), subclassType); break; default: throw new ProtoException("Invalid ProtoIncludeAttribute data-format: " + pia.DataFormat); } // check for duplicates if (tagsInUse.Contains(pia.Tag)) { throw new InvalidOperationException( string.Format("Duplicate tag {0} detected in sub-type {1}", pia.Tag, subclassType.Name)); } tagsInUse.Add(pia.Tag); prop.Init(pia.Tag, pia.DataFormat, PropertyFactory.GetPassThru <T>(), null, true, null); subclassList.Add(new KeyValuePair <Type, Property <T, T> >(subclassType, prop)); } subclasses = subclassList.ToArray(); writeProps = writePropList.ToArray(); readProps = readPropList.ToArray(); // this must be last; this lets other threads see the data } catch (Exception ex) { readProps = writeProps = null; subclasses = null; Debug.WriteLine("Build() failed for type: " + typeof(T).AssemblyQualifiedName); Debug.WriteLine(ex); throw; } finally { Monitor.Exit(lockToken); } }