【问题标题】:Invoking a predicate throws NullReferenceException调用谓词抛出 NullReferenceException
【发布时间】:2014-02-14 06:02:40
【问题描述】:

我有不同的属性可以提供一个值,我想返回第一个满足指定条件的属性。

问题是当其中一个源是classnull 时,我确实得到了一个不错的对象引用,没有设置为对象的实例。

无论是在Func<T,bool> 还是Expression<Func<Media,T>>,我都找不到一个属性来检查当前提供程序的无效性。

你知道如何检查函数目标的无效性吗?

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; }

    // ...

}

【问题讨论】:

  • 我在代码中没有看到AudioSummary,除了cmets..
  • 我已将属性添加到代码中,并对类进行了修剪定义。

标签: c# null predicate


【解决方案1】:

有几种解决方法可以解决您想要实现的目标。

  1. 将表达式调用包装在 try-catch 块中

    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);
      }
      ...
    }
    
  2. 在将 Null 传递给 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;
      }
    }
    
  3. 使用IfNotNull 扩展方法,它的作用与#2 相同,但更高级

    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;
      }
    }
    ...
    

    致谢 IfNotNull 扩展方法转到:hereherehere

  4. 使用Maybe 扩展方法:maybe.codeplex.com(免责声明:我没有测试过这个,但在#3credits 链接中提到)

【讨论】:

  • @Aybe 我很高兴它有帮助……
【解决方案2】:

在调用TryGetValue() 之前检查空对象sAudioSummary,因为如果AudioSummary 为空,您将无法访问属性AudioSummary.Tempo

【讨论】:

    猜你喜欢
    • 2013-05-30
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多