Пример #1
0
        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);
            }
        }