ObjectExtensions
Object extensions.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Namotion.Reflection
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public static class ObjectExtensions
{
public static bool DisableNullabilityValidation { get; set; }
public static bool HasProperty([System.Runtime.CompilerServices.Nullable(2)] this object obj, string propertyName)
{
return ((obj != null) ? obj.GetType().GetRuntimeProperty(propertyName) : null) != (PropertyInfo)null;
}
[System.Runtime.CompilerServices.NullableContext(2)]
public static T TryGetPropertyValue<T>(this object obj, [System.Runtime.CompilerServices.Nullable(1)] string propertyName, T defaultValue = default(T))
{
PropertyInfo propertyInfo = (obj != null) ? obj.GetType().GetRuntimeProperty(propertyName) : null;
if (!(propertyInfo == (PropertyInfo)null))
return (T)propertyInfo.GetValue(obj);
return defaultValue;
}
public static bool HasValidNullability(this object obj, bool checkChildren = true)
{
return !obj.ValidateNullability(checkChildren).Any();
}
[System.Runtime.CompilerServices.NullableContext(2)]
public static void EnsureValidNullability(this object obj, bool checkChildren = true)
{
if (obj != null)
ValidateNullability(obj, obj.GetType().ToContextualType(), checkChildren ? new HashSet<object>() : null, null, false);
}
public static IEnumerable<string> ValidateNullability(this object obj, bool checkChildren = true)
{
List<string> list = new List<string>();
ValidateNullability(obj, obj.GetType().ToContextualType(), checkChildren ? new HashSet<object>() : null, list, false);
return list;
}
private static void ValidateNullability(object obj, ContextualType type, [System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] HashSet<object> checkedObjects, [System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] List<string> errors, bool stopFirstFail)
{
if (!DisableNullabilityValidation && (!stopFirstFail || errors == null || !errors.Any()) && (checkedObjects == null || checkedObjects.Add(obj))) {
if (checkedObjects != null) {
IDictionary dictionary = obj as IDictionary;
if (dictionary != null) {
foreach (object item in dictionary.Keys.Cast<object>().Concat(dictionary.Values.Cast<object>())) {
ValidateNullability(item, type.GenericArguments[1], checkedObjects, errors, stopFirstFail);
}
return;
}
}
if (checkedObjects != null) {
IEnumerable enumerable = obj as IEnumerable;
if (enumerable != null && !(obj is string)) {
ContextualType contextualType = type.ElementType ?? type.GenericArguments[0];
foreach (object item2 in enumerable.Cast<object>()) {
if (item2 == null) {
if (contextualType.Nullability == Nullability.NotNullable) {
if (errors == null)
throw new InvalidOperationException("The object's nullability is invalid, item in enumerable.");
errors.Add(contextualType.Type.Name);
if (stopFirstFail)
break;
}
} else
ValidateNullability(item2, contextualType, checkedObjects, errors, stopFirstFail);
}
return;
}
}
if (!type.TypeInfo.IsValueType) {
ContextualPropertyInfo[] contextualProperties = type.Type.GetContextualProperties();
int num = 0;
ContextualPropertyInfo contextualPropertyInfo;
while (true) {
if (num >= contextualProperties.Length)
return;
contextualPropertyInfo = contextualProperties[num];
if (!contextualPropertyInfo.PropertyType.IsValueType && contextualPropertyInfo.CanRead && !contextualPropertyInfo.IsAttributeDefined<CompilerGeneratedAttribute>(true)) {
object value = contextualPropertyInfo.GetValue(obj);
if (value == null) {
if (contextualPropertyInfo.Nullability == Nullability.NotNullable) {
if (errors == null)
break;
errors.Add(contextualPropertyInfo.Name);
if (stopFirstFail)
return;
}
} else if (checkedObjects != null) {
ValidateNullability(value, contextualPropertyInfo.PropertyType, checkedObjects, errors, stopFirstFail);
}
}
num++;
}
throw new InvalidOperationException("The object's nullability is invalid, property: " + contextualPropertyInfo.PropertyType.Type.FullName + "." + contextualPropertyInfo.Name);
}
}
}
}
}