Skip to content

Commit

Permalink
fix If Property Value Is Null GetToStringValue will get System.NullRe…
Browse files Browse the repository at this point in the history
…ferenceException #1
  • Loading branch information
shps951023 committed Mar 24, 2019
1 parent 31790e7 commit 6152ad5
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 31 deletions.
2 changes: 1 addition & 1 deletion BenchmarkTest/Program.cs
Expand Up @@ -32,7 +32,7 @@ public class BenchmarkBase
public void ReflectionToString() => Data.Select(instance => {
var type = instance.GetType();
var props = type.GetProperties();
return props.ToDictionary(key => key.Name, value => value.GetValue(instance).ToString());
return props.ToDictionary(key => key.Name, value => value.GetValue(instance)?.ToString());
}).ToList();

[Benchmark()]
Expand Down
38 changes: 9 additions & 29 deletions ValueGetter/ValueGetter.cs
Expand Up @@ -11,17 +11,23 @@ public static partial class ValueGetter
{
/// <summary>
/// Compiler Method Like:
/// <code>string GetterFunction(object i) => (i as MyClass).MyProperty1.ToString() ; </code>
/// <code>
/// string GetterToStringFunction(object i) => GetterFunction(i).ToString() ;
/// object GetterFunction(object i) => (i as MyClass).MyProperty1 as object ;
/// </code>
/// </summary>
public static Dictionary<string, string> GetToStringValues<T>(this T instance)
=> instance?.GetType().GetPropertiesFromCache().ToDictionary(key => key.Name, value => value.GetToStringValue<T>(instance));

/// <summary>
/// Compiler Method Like:
/// <code>string GetterFunction(object i) => (i as MyClass).MyProperty1.ToString() ; </code>
/// <code>
/// string GetterToStringFunction(object i) => GetterFunction(i).ToString() ;
/// object GetterFunction(object i) => (i as MyClass).MyProperty1 as object ;
/// </code>
/// </summary>
public static string GetToStringValue<T>(this PropertyInfo propertyInfo, T instance)
=> instance != null ? ValueGetterCache<T, string>.GetOrAddToStringFuntionCache(propertyInfo)(instance) : null;
=> instance != null ? ValueGetterCache<T, object>.GetOrAddFunctionCache(propertyInfo)(instance)?.ToString() : null;
}

public static partial class ValueGetter
Expand All @@ -43,7 +49,6 @@ public static object GetObjectValue<T>(this PropertyInfo propertyInfo, T instanc

internal partial class ValueGetterCache<TParam, TReturn>
{
private static readonly ConcurrentDictionary<int, Func<TParam, TReturn>> ToStringFunctions = new ConcurrentDictionary<int, Func<TParam, TReturn>>();
private static readonly ConcurrentDictionary<int, Func<TParam, TReturn>> Functions = new ConcurrentDictionary<int, Func<TParam, TReturn>>();
}

Expand All @@ -68,31 +73,6 @@ internal partial class ValueGetterCache<TParam, TReturn>
}
}

internal partial class ValueGetterCache<TParam, TReturn>
{
internal static Func<TParam, TReturn> GetOrAddToStringFuntionCache(PropertyInfo propertyInfo)
{
var key = propertyInfo.MetadataToken;
if (ToStringFunctions.TryGetValue(key, out Func<TParam, TReturn> func))
return func;
return (ToStringFunctions[key] = GetCastObjectAndToStringFunction(propertyInfo));
}

private static Func<TParam, TReturn> GetCastObjectAndToStringFunction(PropertyInfo prop)
{
var propType = prop.PropertyType;
var toStringMethod = propType.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(p => p.Name == "ToString").First();

var instance = Expression.Parameter(typeof(TParam), "i");
var convert = Expression.TypeAs(instance, prop.DeclaringType);
var property = Expression.Property(convert, prop);
var tostring = Expression.Call(property, toStringMethod);
var lambda = Expression.Lambda<Func<TParam, TReturn>>(tostring, instance);

return lambda.Compile();
}
}

public static partial class PropertyCacheHelper
{
private static readonly Dictionary<RuntimeTypeHandle, IList<PropertyInfo>> TypePropertiesCache = new Dictionary<RuntimeTypeHandle, IList<PropertyInfo>>();
Expand Down
10 changes: 9 additions & 1 deletion ValueGetterTests/ToStringValueHelperTests.cs
Expand Up @@ -112,7 +112,7 @@ public void IssueForUpcastError()
}

[TestMethod]
public void PropNull()
public void IstanceIsNull()
{
MyClass data = null;
var props = typeof(MyClass).GetProperties();
Expand All @@ -122,5 +122,13 @@ public void PropNull()
var result = prop.GetObjectValue(data);
}
}

[TestMethod]
public void PropertyValueIsNull()
{
MyClass data = new MyClass { MyProperty2=null} ;
var result = data.GetToStringValues()["MyProperty2"] ; //System.NullReferenceException: 'Object reference not set to an instance of an object.'
Assert.IsNull(result);
}
}
}

0 comments on commit 6152ad5

Please sign in to comment.