Пример #1
0
        /// <summary>
        /// Traverse the given instance
        /// </summary>
        /// <param name="instance">The object instance you want to traverse</param>
        /// <param name="maxDepth">The max depth you find appropriate</param>
        /// <param name="listener">The listener that will be notified when we find something</param>
        public virtual void TraverseInstance(object instance, int maxDepth, IInstanceListener listener)
        {
            if (!ShouldRecurse(instance.GetType()))
            {
                throw new InstanceTraversalException($"{instance.GetType()} is not a type that can be traversed.");
            }

            var context = new InstanceTraversalContext
            {
                Instance = instance,
                MaxDepth = maxDepth
            };

            //
            // constructors
            // we are doing constructors in the non-recursive part
            // as we are not interested in constructors of field
            // and property types
            //
            var constructors = instance.GetType().GetTypeInfo().GetConstructors();

            foreach (var constructorInfo in constructors)
            {
                listener.OnConstructor(constructorInfo, context);
            }

            Worker(instance, listener, context);
        }
Пример #2
0
 /// <summary>
 /// Call OnField or OnProperty for the given member
 /// </summary>
 private void CallListener(IInstanceListener listener, InstanceTraversalContext context, MemberInfo memberInfo, Func <object> valueGetter)
 {
     if (memberInfo.MemberType == MemberTypes.Field)
     {
         listener.OnField((FieldInfo)memberInfo, valueGetter, context);
     }
     else
     {
         listener.OnProperty((PropertyInfo)memberInfo, valueGetter, context);
     }
 }
Пример #3
0
        private void Worker(object instance, IInstanceListener listener, InstanceTraversalContext context)
        {
            var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;

            var typeInfo = instance.GetType().GetTypeInfo();

            //
            // fields
            //
            var fields = typeInfo.GetFields(bindingFlags);

            foreach (var fieldInfo in fields)
            {
                if (!IsBackingField(fieldInfo))
                {
                    FieldAndPropertyHandler(listener, fieldInfo, context, instance);
                }
            }

            //
            // properties
            //
            var props = typeInfo.GetProperties(bindingFlags);

            foreach (var propertyInfo in props)
            {
                if (!IsIndexProperty(propertyInfo))
                {
                    FieldAndPropertyHandler(listener, propertyInfo, context, instance);
                }
            }

            //
            // methods
            //
            var methods = typeInfo.GetMethods(bindingFlags);

            foreach (var methodInfo in methods)
            {
                if (
                    methodInfo.DeclaringType != typeof(System.Object) && // do not "announce" methods like Object.ToString
                    !IsBackingMethod(methodInfo)    // do not "announce" auto property backing methods
                    )
                {
                    listener.OnMethod(methodInfo, context);
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Traverse the given instance
        /// </summary>
        /// <param name="instance">The object instance you want to traverse</param>
        /// <param name="maxDepth">The max depth you find appropriate</param>
        /// <param name="listener">The listener that will be notified when we find something</param>
        public virtual void TraverseInstance(object instance, int maxDepth, IInstanceListener listener)
        {
            var context = new InstanceTraversalContext
            {
                Instance = instance,
                MaxDepth = maxDepth
            };

            //
            // constructors
            // we are doing constructors in the non-recursive part
            // as we are not interested in constructors of field
            // and property types
            //
            var constructors = instance.GetType().GetTypeInfo().GetConstructors();

            foreach (var constructorInfo in constructors)
            {
                listener.OnConstructor(constructorInfo, context);
            }

            Worker(instance, listener, context);
        }
Пример #5
0
        /// <summary>
        /// Field and properties are actually quite similar
        /// in this context. This method contains "generic" handling
        /// of both types, so we avoid duplication.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if we somehow try to iterate something that is not an IEnumerable</exception>
        private void FieldAndPropertyHandler(IInstanceListener listener, MemberInfo memberInfo, InstanceTraversalContext context, object instance)
        {
            Func <object> valueGetter = () => memberInfo.GetValue(instance);

            CallListener(listener, context, memberInfo, valueGetter);

            var valueType = memberInfo.GetTypeOfValue();

            if (ShouldIterate(valueType))
            {
                object value = valueGetter.Invoke();

                if (value != null)
                {
                    if (value is IDictionary)
                    {
                        var dictionary = value as IDictionary;

                        foreach (DictionaryEntry entry in dictionary)
                        {
                            context.BreadcrumbStack.Push($"{memberInfo.Name}[{entry.Key}]");
                            CallListener(listener, context, memberInfo, () => entry.Value);

                            if (ShouldRecurse(entry.Value.GetType()))
                            {
                                if (context.CanGoDeeper())
                                {
                                    Worker(entry.Value, listener, context);
                                }
                                else
                                {
                                    listener.OnMaxDepthReached(context);
                                }
                            }

                            context.BreadcrumbStack.Pop();
                        }
                    }
                    else
                    {
                        var enumerable = value as IEnumerable;

                        if (enumerable == null)
                        {
                            throw new InvalidOperationException($"Trying to iterate over {context.BreadcrumbAsString}.{memberInfo.Name}, but could not cast to IEnumerable.");
                        }

                        var index = 0;
                        foreach (var element in enumerable)
                        {
                            // If TraverseInstance is called directly on a list with capacity greater than the size
                            // Then null elements will be present
                            if (element == null)
                            {
                                continue;
                            }
                            context.BreadcrumbStack.Push($"{memberInfo.Name}[{index}]");
                            CallListener(listener, context, memberInfo, () => element);

                            if (ShouldRecurse(element.GetType()))
                            {
                                if (context.CanGoDeeper())
                                {
                                    Worker(element, listener, context);
                                }
                                else
                                {
                                    listener.OnMaxDepthReached(context);
                                }
                            }

                            context.BreadcrumbStack.Pop();
                            index++;
                        }
                    }
                }
            }

            else if (ShouldRecurse(valueType))
            {
                //
                // recursion
                //
                if (context.CanGoDeeper())
                {
                    object value = valueGetter.Invoke();

                    if (value != null)
                    {
                        context.BreadcrumbStack.Push(memberInfo.Name);
                        Worker(value, listener, context);
                        context.BreadcrumbStack.Pop();
                    }
                }
                else
                {
                    listener.OnMaxDepthReached(context);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Call OnField or OnProperty for the given member
        /// </summary>
        private static IInstanceListenerOnFieldOrPropResult CallListener(IInstanceListener listener, InstanceTraversalContext context, MemberInfo memberInfo, Func <object> valueGetter)
        {
            if (memberInfo.MemberType == MemberTypes.Field)
            {
                return(listener.OnField((FieldInfo)memberInfo, valueGetter, context));
            }

            return(listener.OnProperty((PropertyInfo)memberInfo, valueGetter, context));
        }