Last active
June 7, 2017 15:06
-
-
Save stdray/4e755a1dcaa66e46fe97c932f57df154 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| void Main() | |
| { | |
| var obj = new object(); | |
| HasNullPropertyOrFields(obj).Dump(); | |
| } | |
| const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; | |
| bool HasNullPropertyOrFields(object obj) | |
| { | |
| var visited = new HashSet<object>(ReferenceEqualityComparer.Instance); | |
| return HasNullPropertyOrFieldsImpl(visited, obj); | |
| } | |
| bool HasNullPropertyOrFieldsImpl(HashSet<object> visited, object obj) | |
| { | |
| if (obj == null) | |
| return true; | |
| var type = obj.GetType(); | |
| if(type.IsClass && !visited.Add(obj)) | |
| return false; | |
| var properties = type.GetProperties(flags).Select(p => new { Type = p.PropertyType, Values = GetValues(p.GetValue(obj)) }); | |
| var fields = type.GetFields(flags).Select(p => new { Type = p.FieldType, Values = GetValues(p.GetValue(obj)) }); | |
| var members = properties.Concat(fields).ToList(); | |
| return members.Any(m => m.Values == null || m.Values.Any(v => v == null)) | |
| || members.Any(m => m.Values.Any(HasNullPropertyOrFields)); | |
| } | |
| IReadOnlyCollection<object> GetValues(object obj) | |
| { | |
| if(obj == null) | |
| return null; | |
| var seq = obj as IEnumerable; | |
| if (seq != null) | |
| { | |
| var count = TryGetCollectionCount(seq); | |
| var values = count.HasValue && count.Value >= 0 ? new List<object>(count.Value) : new List<object>(); | |
| var enumerator = seq.GetEnumerator(); | |
| if(enumerator != null) | |
| while(enumerator.MoveNext()) | |
| values.Add(enumerator.Current); | |
| return values; | |
| } | |
| else | |
| return new[] { obj }; | |
| } | |
| int? TryGetCollectionCount(IEnumerable seq) | |
| { | |
| var collection = seq as ICollection; | |
| if(collection != null) | |
| return collection.Count; | |
| return null; | |
| } | |
| public class ReferenceEqualityComparer : IEqualityComparer<object> | |
| { | |
| public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); | |
| bool IEqualityComparer<object>.Equals(object x, object y) | |
| { | |
| return ReferenceEquals(x, y); | |
| } | |
| public int GetHashCode(object obj) | |
| { | |
| return RuntimeHelpers.GetHashCode(obj); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment