I have different properties that can provide a value and I would like to return the first one that satisfies a specified condition.
The problem is when one of the sources is a class
and is null
, I do get a nice Object reference not set to an instance of an object. .
I can't find a property to check against the nullity of the current provider, whether on the Func<T,bool>
or the Expression<Func<Media,T>>
.
Do you know how can I check against the nullity of a function target ?
public int TempoInteger
{
get
{
double result;
// In this case, AudioSummary is a class that can be null
if (TryGetValue(out result, s => s > 0.0d, s => s.TempoBass, s => s.AudioSummary.Tempo))
{
return (int)Math.Round(result);
}
return -1;
}
}
private AudioSummary AudioSummary {get; set;}
/// <summary>
/// Tries to get a value from multiple expressions, first expression value that satisfies the predicate will be returned. If no value satisifes the predicate the default value of <typeparamref name="T"/> will be returned.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="result"></param>
/// <param name="predicate"></param>
/// <param name="expressions"></param>
/// <returns></returns>
private bool TryGetValue<T>(out T result, Func<T, bool> predicate, params Expression<Func<Media, T>>[] expressions)
{
foreach (var expression in expressions)
{
Func<Media, T> func = expression.Compile();
// 'System.NullReferenceException' occurs here when AudioSummary is null
T t = func(this);
var b = predicate(t);
if (b)
{
result = t;
return true;
}
}
result = default(T);
return false;
}
public sealed class AudioSummary
{
[JsonProperty("tempo")]
public double Tempo { get; set; }
// ...
}
There's several workaround for what you're trying to achieve.
Wrap the expression invocation inside a try-catch block
private bool TryGetValue<T>( out T result, Func<T, bool> predicate, params Expression<Func<Media, T>>[] expressions) { ... T t; try { t = func(this); } catch (NullReferenceException) { t = default(T); } ... }
Validate the expression for Null
before passing it to TryGetValue()
public int TempoInteger { get { double result; if (TryGetValue(out result, s => s > 0.0d, s => s.TempoBass, s => s.AudioSummary != null ? s.AudioSummary.Tempo : 0.0d)) { return (int)Math.Round(result); } return -1; } }
Use the IfNotNull
extension method, which does the same thing as point #2
but fancier
public static class IfNotNullExtensionMethod { public static T2 IfNotNull<T1, T2>(this T1 t, Func<T1, T2> fn) where T1: class { return t != null ? fn(t) : default(T2); } } ... public int TempoInteger { get { double result; if (TryGetValue(out result, s => s > 0.0d, s => s.TempoBass, s => s.AudioSummary.IfNotNull(x => x.Tempo))) { return (int)Math.Round(result); } return -1; } } ...
Credits for the IfNotNull
extension methods goes to: here , here , and here
Use the Maybe
extensions method: maybe.codeplex.com . (disclaimer: I haven't tested this one, but it's mentioned in point #3
credits links)
调用之前TryGetValue()
检查空物体s
和AudioSummary
因为如果AudioSummary
为空,你不能让财产AudioSummary.Tempo
。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.