【问题标题】:How can I avoid NullReferenceException when overloading the constructor?重载构造函数时如何避免 NullReferenceException?
【发布时间】:2016-09-19 13:01:26
【问题描述】:

为了更好地说明我的情况,我做了一个例子

void Main()
{
    var a = new Lol(null);
}

public class Lol
{
    public Lol(string a, string b)
    {
        if(a == null || b == null)
        {
            throw new Exception();
        }
    }

    public Lol(Tuple<string, string> k)
        : this(k.Item1, k.Item2)
    {
    }
}

在这种情况下,我在第二个构造函数中得到了NullReferenceException。有没有办法从方法内部处理它,保持相同的结构,或者我应该创建一个私有方法并让两个构造函数都调用这个方法?

【问题讨论】:

  • 如果你有 C# 6 (VS 2015) 你可以做this(k?.Item1, k?.Item2)
  • 或者不要调用this...并在第二个构造函数中执行它,这可能更合适,因为您在那里执行不同的空检查。
  • 不要调用这个。在实际的第二个构造函数中处理任何赋值。然后,您可以在构造函数本身内部进行 null 检查。
  • 或者您将第一个 ctor 更改为 Lol(str a, str b) : this(Tuple.Create(a, b)),第二个 ctor 检查整个元组及其项。
  • @DavidG 我认为你的方法是制作结构良好的代码的最佳方式

标签: c# nullreferenceexception constructor-overloading


【解决方案1】:

您可以将逻辑抽象为辅助方法,并让两个构造函数都调用该辅助方法。

public class Lol
{
    public Lol(string a, string b)
    {
        LolHelper(a, b);
    }

    public Lol(Tuple<string, string> k)
    {
        (k!=null)
            ?LolHelper(k.Item1, k.Item2)
            :LolHelper(null, null);
    }

    private void LolHelper(string a, string b)
    {
        if(a == null || b == null)
        {
            throw new Exception();
        }
    }
}

【讨论】:

    【解决方案2】:

    在不改变任何逻辑的情况下,你可以这样做:

    public class Lol
    {
        public Lol(string a, string b)
        {
            if(a == null || b == null)
            {
                throw new Exception();
            }
        }
    
        public Lol(Tuple<string, string> k)
        : this(k != null ? k.Item1 : null, k != null ? k.Item2 : null)
        {
        }
    }
    

    但是在更复杂的情况下,这可能不起作用(尽管您不应该在构造函数链中放置任何复杂的逻辑)。

    【讨论】:

      【解决方案3】:

      首先不在构造函数中传递 null。如果您希望与 a 和 b 对应的字段或属性为 null,只需将其放入构造函数中,如下所示:

      private string a;
      private string b;
      public Lol()
              {
                  a= null;
                  b= null;
              }
      

      在 Main() 中使用:

      var a = new Lol();
      

      如果要传递值,而不是 null,请使用适当的构造函数。

      【讨论】:

      • 我必须检查元组也不为空,我不需要无参数构造函数
      • @Phate01。您的意思是检查元组是否事先初始化。是否有一个您不会初始化它的脚本。如果不是,那么您不需要检查它是否为空。在另一种情况下,我为误解你而道歉。顺便说一句,最好在属性内部进行检查。
      【解决方案4】:

      这应该适用于带有 C#6 的 VS2015:

      this(k?.Item1, k?.Item2)
      

      最后:

      void Main()
      {
          var a = new Lol(null);
      }
      
      public class Lol
      {
          public Lol(string a, string b)
          {
              if(a == null || b == null)
                  throw new Exception();
          }
      
          public Lol(Tuple<string, string> k)
              : this(k?.Item1, k?.Item2)
          {
          }
      }
      

      【讨论】:

      • 其实这不依赖于.Net版本,而是编译器的版本,特别是VS 2015的C#6。
      • 感谢您的澄清,我将编辑我的答案,然后:)
      【解决方案5】:

      这是设计使然,您需要检查第二个构造函数

      public Lol(Tuple<string, string> k)
      
      {
          if(k == null || k.Item1 == null || k.Item2 == null)
          {
              throw new Exception();
          }
      }
      

      【讨论】:

      • 如何从这里调用另一个构造函数?
      • 你没有。设置每个类的字段,并使用通用初始化函数完成其余工作。
      【解决方案6】:

      我的方法是扩展方法:

      public static class Requirements
      {
          public static T NotNull<T>(this T value, string parameterName, string message)
              where T : class =>
              value ?? throw new ArgumentNullException(parameterName, message);
      
          public static T NotNull<T>(this T value, string parameterName)
              where T : class =>
              value ?? throw new ArgumentNullException(parameterName);
      }
      

      用法:

      public class Lol
      {
          public Lol(string a, string b)
          {
              if(a == null || b == null)
              {
                  throw new ArgumentNullException();
              }
          }
      
          public Lol(Tuple<string, string> k)
              : this(k.NotNull(nameof(k)).Item1, k.NotNull(nameof(k)).Item2)
          {
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-17
        • 2016-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多