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);
            }
Exemple #3
0
 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
            }
        }
Exemple #5
0
        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);
            }
        }