Reflection helpers for accessing properties.
コード例 #1
0
ファイル: ObjectGraphScanner.cs プロジェクト: zuohu/NLog
        /// <remarks>ISet is not there in .net35, so using HashSet</remarks>
        private static void ScanProperties <T>(bool aggressiveSearch, List <T> result, object o, int level, HashSet <object> visitedObjects)
            where T : class
        {
            if (o == null)
            {
                return;
            }

            var type = o.GetType();

            try
            {
                if (type == null || !type.IsDefined(typeof(NLogConfigurationItemAttribute), true))
                {
                    return;
                }
            }
            catch (System.Exception ex)
            {
                InternalLogger.Info(ex, "{0}Type reflection not possible for: {1}. Maybe because of .NET Native.", new string(' ', level), o.ToString());
                return;
            }

            if (visitedObjects.Contains(o))
            {
                return;
            }

            visitedObjects.Add(o);

            if (InternalLogger.IsTraceEnabled)
            {
                InternalLogger.Trace("{0}Scanning {1} '{2}'", new string(' ', level), type.Name, o);
            }

            if (o is T t)
            {
                result.Add(t);
                if (!aggressiveSearch)
                {
                    return;
                }
            }

            foreach (PropertyInfo prop in PropertyHelper.GetAllReadableProperties(type))
            {
                if (prop == null || prop.PropertyType == null || prop.PropertyType.IsPrimitive() || prop.PropertyType.IsEnum() || prop.PropertyType == typeof(string))
                {
                    continue;
                }

                try
                {
                    if (prop.IsDefined(typeof(NLogConfigurationIgnorePropertyAttribute), true))
                    {
                        continue;
                    }
                }
                catch (System.Exception ex)
                {
                    InternalLogger.Info(ex, "{0}Type reflection not possible for property {1}. Maybe because of .NET Native.", new string(' ', level + 1), prop.Name);
                    continue;
                }

                object value = prop.GetValue(o, null);
                if (value == null)
                {
                    continue;
                }

                if (InternalLogger.IsTraceEnabled)
                {
                    InternalLogger.Trace("{0}Scanning Property {1} '{2}' {3}", new string(' ', level + 1), prop.Name, value.ToString(), prop.PropertyType.Namespace);
                }

                if (value is IList list)
                {
                    //try first icollection for syncroot
                    List <object> elements;
                    lock (list.SyncRoot)
                    {
                        elements = new List <object>(list.Count);
                        //no foreach. Even .Cast can lead to  Collection was modified after the enumerator was instantiated.
                        for (int i = 0; i < list.Count; i++)
                        {
                            var item = list[i];
                            elements.Add(item);
                        }
                    }
                    ScanPropertiesList(aggressiveSearch, result, elements, level + 1, visitedObjects);
                }
                else
                {
                    if (value is IEnumerable enumerable)
                    {
                        //new list to prevent: Collection was modified after the enumerator was instantiated.
                        var elements = enumerable as IList <object> ?? enumerable.Cast <object>().ToList();
                        //note .Cast is tread-unsafe! But at least it isn't a ICollection / IList
                        ScanPropertiesList(aggressiveSearch, result, elements, level + 1, visitedObjects);
                    }
                    else
                    {
#if NETSTANDARD
                        if (!prop.PropertyType.IsDefined(typeof(NLogConfigurationItemAttribute), true))
                        {
                            continue;   // .NET native doesn't always allow reflection of System-types (Ex. Encoding)
                        }
#endif
                        ScanProperties(aggressiveSearch, result, value, level + 1, visitedObjects);
                    }
                }
            }
        }
コード例 #2
0
        private static void ScanProperties <T>(List <T> result, object o, int level, Dictionary <object, int> visitedObjects)
            where T : class
        {
            if (o == null)
            {
                return;
            }

            if (!o.GetType().IsDefined(typeof(NLogConfigurationItemAttribute), true))
            {
                return;
            }

            if (visitedObjects.ContainsKey(o))
            {
                return;
            }

            visitedObjects.Add(o, 0);

            var t = o as T;

            if (t != null)
            {
                result.Add(t);
            }

            if (InternalLogger.IsTraceEnabled)
            {
                InternalLogger.Trace("{0}Scanning {1} '{2}'", new string(' ', level), o.GetType().Name, o);
            }

            foreach (PropertyInfo prop in PropertyHelper.GetAllReadableProperties(o.GetType()))
            {
                if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsEnum || prop.PropertyType == typeof(string) || prop.IsDefined(typeof(NLogConfigurationIgnorePropertyAttribute), true))
                {
                    continue;
                }

                object value = prop.GetValue(o, null);
                if (value == null)
                {
                    continue;
                }

                var enumerable = value as IEnumerable;
                if (enumerable != null)
                {
                    //new list to prevent: Collection was modified after the enumerator was instantiated.
                    var elements = new List <object>(enumerable.Cast <object>());

                    foreach (object element in elements)
                    {
                        ScanProperties(result, element, level + 1, visitedObjects);
                    }
                }
                else
                {
                    ScanProperties(result, value, level + 1, visitedObjects);
                }
            }
        }