2

以下模式在我的代码中很常见:一个类有多个构造函数。一个是“指定构造函数”,其他是为了方便。代码可能如下所示:

class Foo 
{
  Foo(int bar, string baz) 
  {
    this.Bar = bar;
    this.Baz = baz;
  }

  Foo()
    : this(0, "Empty baz")
  {
  }

  Foo(Foo f)
    : this(f.Bar, f.Baz)
  {
  }

  int Bar {get;set;}
  string Baz {get;set;}
}

在无参数构造函数调用的情况下this(...),这工作正常。但是,如果有人将null作为参数传递给复制构造函数Foo(Foo),则结果将是由于表达式而导致的空引用异常f.Bar。因为我希望看到 ArgumentNullException,所以在这种情况下我通常会偏离模式并“手动”实现构造函数,这会导致重复代码。有没有一种优雅的方法来避免这种情况,即拥有一个指定的构造函数并仍然为其他构造函数执行参数验证?

编辑:这个例子只是为了描述这个问题。在现实世界的例子中,会有更复杂的参数验证逻辑和初始化代码。

4

3 回答 3

2

您可以按如下方式检查:

class Foo
{
    private static Foo ThrowIfNull(Foo foo)
    {
        if (foo == null) throw new ArgumentNullException("foo");
        return foo;
    }

    ...

    Foo(Foo f) : this (ThrowIfNull(f).Bar, f.Baz)
    {
    }
}

它会稍微丢掉你的堆栈跟踪,但不会太多。

于 2012-07-17T10:41:02.677 回答
1

您应该始终检查从类范围之外获得的参数。

于 2012-07-17T10:34:01.087 回答
0

您确定此代码无法转换为:(?)

  Foo(Foo f)
  {
       if(f != null) 
       {
            Bar = f.Bar;
            Baz = f.Baz;
       }
       else
       {
           throw new ArgumentNullException("f");
       }
  }

老实说,我相信这是您的情况。为什么要把事情复杂化?

您希望在构建时设置一些属性,您可以在构造函数本身中实现它。因为您想避免 1、2 或 3 行,所以您正在尝试发明一个轮子!;)

选项 B··· 更新!!

还有另一种方法。覆盖您的用例但使用可选参数单个构造函数怎么样?

您的构造函数将是这样的:

Foo(int bar = -1, string baz = null, Foo f = null) 
  {
    if(bar >= 0 && !string.IsNullOrEmpty(baz)) 
    {
       Bar = bar;
       Baz = baz;
    }
    else if(f != null) 
    {
       Bar = f.Bar;
       Baz = f.Baz;
    }
    else
    {
        Bar = 0;
        Baz = "Empty baz";
    }
  }

根据您调用此构造函数的方式,它会做某事或其他事情。

于 2012-07-17T10:41:21.483 回答