【问题标题】:Call one constructor from the body of another in C#在 C# 中从另一个的主体调用一个构造函数
【发布时间】:2011-09-27 21:11:26
【问题描述】:

我需要从另一个构造函数的主体中调用一个构造函数。我该怎么做?

基本上

class foo {
    public foo (int x, int y)
    {
    }

    public foo (string s)
    {
        // ... do something

        // Call another constructor
        this (x, y); // Doesn't work
        foo (x, y); // neither
    }
}

【问题讨论】:

  • 像 public foo (int x, int y , string s) 这样的构造函数怎么样

标签: c# constructor


【解决方案1】:

你不能。

您必须找到一种方法来链接构造函数,如下所示:

public foo (int x, int y) { }
public foo (string s) : this(XFromString(s), YFromString(s)) { ... }

或将您的构造代码移动到通用设置方法中,如下所示:

public foo (int x, int y) { Setup(x, y); }
public foo (string s)
{
   // do stuff
   int x = XFromString(s);
   int y = YFromString(s);
   Setup(x, y);
}

public void Setup(int x, int y) { ... }

【讨论】:

  • 请注意,一般情况下,setup 方法无法写入 readonly 变量,但构造函数可以将 readonly 变量作为 ref 参数传递给 setup 方法,然后将能够写入其ref 参数,即使它们是只读变量。
  • Setup 方法在大多数情况下应该是私有的
  • 注意在第一个解决方案中XFromStringYFromString 必须是静态方法。这是我最喜欢的方式!
【解决方案2】:

this(x, y)是对的,但必须在构造函数体开始之前:

public Foo(int x, int y)
{
    ...
}

public Foo(string s) : this(5, 10)
{
}

注意:

  • 您只能链接到一个构造函数,thisbase - 当然,该构造函数可以链接到另一个构造函数。
  • 构造函数主体在链式构造函数调用之后执行。没有办法先执行构造函数体。
  • 您不能在其他构造函数的参数中使用this,包括调用实例方法 - 但您可以调用静态方法。
  • 任何实例变量初始化器在链式调用之前执行

我的article about constructor chaining 中有更多信息。

【讨论】:

  • 当你有这样的东西时尤其烦人:class A{ public A(IEnumerable<int> items) {...} public A(MyClass c) : this(c.Items) { ... } }。只有在访问 c 之后,才会执行第二个 ctor 中的任何空检查。如果 c 为空,第二个 ctor 将抛出 NRE,而不是首选的 ArgumentNullException。如果你想让你的字段只读,除了在两个ctors中实现相同的逻辑之外别无他法。或者是否有更好的方法来做到这一点?
  • @DanielHilgarth:是的。有一个通用的扩展方法,它检查空值,否则返回原始值。然后你可以做this(c.ThrowIfNull("c").Items)
  • 谢谢,这也是我唯一能想到的。只是想编辑我的评论...虽然不确定这是否是一个好方法,因为到目前为止我还没有在任何地方看到它...
  • @DanielHilgarth:我认为没关系,是的。
  • 一个问题:参数的评估顺序是固定的还是可以改变的实现细节?因为如果您需要访问多个属性,它会变得非常笨拙:public PcmSample(IPcmSample other) : this(other.ThrowIfNull("other").Channels, other.ThrowIfNull("other").Items)
【解决方案3】:

要显式调用基类和此类构造函数,您需要使用下面给出的语法(注意,在 C# 中,您不能像在 C++ 中那样使用它来初始化字段):

class foo
{
    public foo (int x, int y)
    {
    }

    public foo (string s) : this(5, 6)
    {
        // ... do something
    }
}

//编辑:请注意,您在示例中使用了 x,y。当然,以这种方式调用 ctor 时给出的值不能依赖于其他构造函数的参数,它们必须以其他方式解析(它们不需要是常量,尽管在上面编辑的代码示例中)。如果xy 是从s 计算出来的,你可以这样做:

public foo (string s) : this(GetX(s), GetY(s))

【讨论】:

  • 小备注:public foo(string s) : this(x, y) 不起作用。 public foo(string s, int x, int y) : this(x, y) 将编译
【解决方案4】:

这不受支持 - 请参阅 Constructors in C#

但是,您可以实现从不同构造函数调用的通用(私有)方法...

【讨论】:

    【解决方案5】:

    我自己也遇到过一两次这个问题...我最终不得不将我在其他构造函数中需要的任何逻辑提取到 private void 方法中并在两个地方调用它。

    class foo
    {
      private void Initialize(int x, int y)
      {
        //... do stuff
      }
    
      public foo(int x, int y)
      {
        Initialize(x, y);
      }
    
      public foo(string s_
      {
        // ... do stuff
    
        Initialize(x, y)
        // ... more stuff
      }
    }
    

    【讨论】:

      【解决方案6】:

      MSDN中MethodBase.Invokedescription有注释

      如果此方法重载用于调用实例构造函数,则 为 obj 提供的对象被重新初始化;也就是说,所有实例 初始化程序被执行。返回值为空。如果一个班级 构造函数被调用,类被重新初始化;也就是说,所有类 初始化程序被执行。返回值为空。

      即您可以通过反射获取构造函数的方法,并在新构造函数的主体中通过Invoke 调用它。 但我没有尝试过。当然,这种解决方案也有很多缺点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-01
        • 1970-01-01
        • 2016-07-03
        • 2020-03-14
        • 1970-01-01
        • 2012-06-22
        相关资源
        最近更新 更多