Skip to content

Instantly share code, notes, and snippets.

@stdray
Last active June 7, 2017 15:06
Show Gist options
  • Select an option

  • Save stdray/4e755a1dcaa66e46fe97c932f57df154 to your computer and use it in GitHub Desktop.

Select an option

Save stdray/4e755a1dcaa66e46fe97c932f57df154 to your computer and use it in GitHub Desktop.
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