Exemple #1
0
        static void AddClassDumpData(
            Type type,
            ClassDumpData classDumpData,
            bool replace)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            TypesDumpDataSync.EnterWriteLock();
            try
            {
                if (!replace && TypesDumpData.TryGetValue(type, out var dumpData))
                {
                    if (dumpData == classDumpData)
                    {
                        return;
                    }

                    throw new InvalidOperationException(
                              $"The type {type.FullName} is already associated with metadata type {TypesDumpData[type].Metadata.FullName} and a DumpAttribute instance.");
                }

                TypesDumpData[type] = classDumpData;
            }
            finally
            {
                TypesDumpDataSync.ExitWriteLock();
            }
        }
Exemple #2
0
        internal void DumpObject(
            object obj,
            Type dumpMetadata           = null,
            DumpAttribute dumpAttribute = null,
            DumpState parentState       = null)
        {
            if (Writer.DumpedBasicValue(obj, dumpAttribute) || Writer.DumpedBasicNullable(obj, dumpAttribute))      // incl. null
            {
                return;
            }

            // resolve the class metadata and the dump attribute
            ClassDumpData classDumpData;
            var           objectType = obj.GetType();

            if (dumpMetadata == null)
            {
                classDumpData = ClassMetadataResolver.GetClassDumpData(objectType);
                if (dumpAttribute != null)
                {
                    classDumpData.DumpAttribute = dumpAttribute;
                }
            }
            else
            {
                classDumpData = new ClassDumpData(dumpMetadata, dumpAttribute);
            }

            // if we're too deep - stop here.
            if (_maxDepth == int.MinValue)
            {
                _maxDepth = classDumpData.DumpAttribute.MaxDepth;
            }

            if (_maxDepth < 0)
            {
                Writer.Write(Resources.DumpReachedMaxDepth);
                return;
            }

            // save here the IsSubExpression flag as it will change if obj is Expression and IsSubExpression==false.
            // but in the end of this method restore the value from this local variable. See below.
            var isSubExpressionStore = IsSubExpression;

            // slow dump vs. run script?
            bool   isTopLevelObject = parentState == null;
            var    buildScript      = UseDumpScriptCache && !obj.IsDynamicObject();
            Script script           = null;

            using (var state = new DumpState(this, obj, classDumpData, buildScript))
            {
                if (buildScript)
                {
                    // does the script exist or is it in process of building
                    if (DumpScriptCache.TryFind(this, obj, classDumpData, out script))
                    {
                        if (script != null)
                        {
                            if (isTopLevelObject)
                            {
                                Writer.Indent(_indentLevel, _indentSize)
                                .WriteLine();
                            }

                            script(obj, classDumpData, this, state);
                        }

                        return;
                    }

                    DumpScriptCache.BuildingScriptFor(this, objectType, classDumpData);
                }
                else
                {
                    if (isTopLevelObject)
                    {
                        Writer.Indent(_indentLevel, _indentSize)
                        .WriteLine();
                    }
                }

                if (!state.DumpedAlready())     // the object has been dumped already (block circular and repeating references)
                {
                    // this object will be dumped below.
                    // Add it to the dumped objects now so that if nested property refers back to it, it won't be dumped in an infinite recursive chain.
                    DumpedObjects.Add(new DumpedObject(obj, objectType));

                    if (!state.DumpedCollection(classDumpData.DumpAttribute, false))   // custom collections are dumped after dumping all other properties (see below *  )
                    {
                        Stack <DumpState> statesWithRemainingProperties = new Stack <DumpState>();
                        Queue <DumpState> statesWithTailProperties      = new Queue <DumpState>();

                        // recursively dump all properties with non-negative order in class inheritance descending order (base classes' properties first)
                        // and if there are more properties  to be dumped put them in the stack
                        if (!DumpedTopProperties(state, statesWithRemainingProperties))
                        {
                            // dump all properties with negative order in class ascending order (derived classes' properties first)
                            DumpRemainingProperties(statesWithRemainingProperties, statesWithTailProperties);

                            // dump all properties with Order=int.MinValue in ascending order (derived classes' properties first)
                            DumpTailProperties(statesWithTailProperties);

                            // * if the object implements IEnumerable and the state allows it - dump the elements.
                            state.DumpedCollection(classDumpData.DumpAttribute, true);
                        }

                        // we are done dumping
                        state.Unindent();
                    }
                }

                if (buildScript && state.DumpScript != null)
                {
                    script = DumpScriptCache.Add(this, objectType, classDumpData, state.DumpScript);
                }

                if (!buildScript)
                {
                    if (isTopLevelObject)
                    {
                        Writer.Unindent(_indentLevel, _indentSize);
                    }
                }
                else
                {
                    if (script != null)
                    {
                        if (isTopLevelObject)
                        {
                            Writer.Indent(_indentLevel, _indentSize)
                            .WriteLine();
                        }

                        script(obj, classDumpData, this, state);
                    }
                }

                // restore here the IsSubExpression flag as it have changed if obj is Expression and IsSubExpression==false.
                IsSubExpression = isSubExpressionStore;
            }
        }