【问题标题】:Calling base constructor in C# [duplicate]在 C# 中调用基本构造函数 [重复]
【发布时间】:2010-10-12 05:21:49
【问题描述】:

我有以下层次结构:

class Base
{
  public Base(string sMessage)
  {
     //Do stuff
  }
}

class Derived : Base
{
  public Derived(string someParams)
  {

   string sMessage = "Blah " + someParams;

   //Here I want to call the base constructor
   //base(sMessage);

  }

}

【问题讨论】:

    标签: c# asp.net


    【解决方案1】:

    我最初错过了 OregonGhost 关于使用静态方法修改参数的评论,结果证明这对我来说是最有用的,所以我想我会为阅读此线程的其他人添加代码示例:

    class Base
    {
        public Base( string sMessage )
        {
            // Do stuff
        }
    }
    
    class Derived : Base
    {
        public Derived( string sMessage ) : base( AdjustParams( sMessage ) )
        {
        }
    
        static string AdjustParams( string sMessage )
        {
            return "Blah " + sMessage;
        }
    }
    

    【讨论】:

      【解决方案2】:

      其实最简单的解决办法是:

      class Base
      {
        public Base(string sMessage)
        {
           //Do stuff
        }
      }
      
      class Derived : Base
      {
        public Derived(string someParams)
          : base("Blah " + someParams)
        {
        }
      
      }
      

      为什么要让它更复杂?

      【讨论】:

      • 是的,我注意到之后 OregonGhost 已经建议了这个..
      【解决方案3】:
      public Derived(string someParams) : base(someParams)
      {
          string sMessage = "Blah " + someParams;
      }
      

      这是你必须这样做的方式。你也许可以把你想调用的代码放在基类的一个受保护的方法中,然后你可以像这样调用它:

      class Base
      {
        public Base(string sMessage)
        {
           ConstructorStuff();
        }
      
        protected Base()
        {
        }
      
        protected void ConstructorStuff()
        {
        }
      }
      
      class Derived : Base
      {
        public Derived(string someParams)
        {    
         string sMessage = "Blah " + someParams;
      
         ConstructorStuff();       
        }    
      }
      

      【讨论】:

      • 这将运行 ConstructorStuff 两次——一次是在派生构造函数之前调用默认基本构造函数时,一次是在派生构造函数执行期间。
      • 呃? Base 没有调用 ConstructorStuff 的默认构造函数?
      • 啊。然后您需要提供一个默认构造函数,否则代码将无法编译,因为您的派生类将需要它。问题仍然存在,默认构造函数也需要使用 ConstructorStuff 并且您需要一个不调用初始化程序的替代方法。
      • 这会让我从一个基本的 C# 问题中错过“太明显而无法打扰”的代码。修改后的代码现在会做他想做的事,不是吗?
      • 现在的问题是每个派生类都需要调用初始化程序。我认为你想要的是默认运行初始化,但如果有必要有办法阻止它。这将完成这项工作,但不是 IMO 的最佳解决方案。
      【解决方案4】:

      如果您确实需要首先运行您的构造函数,那么我建议使用受保护的 Initialize 方法,该方法由您的构造函数调用并执行初始化类的实际工作。您需要提供一个允许跳过初始化的替代构造函数。

      public class Base
      {
      
          public Base() : this(true) { }
      
          protected Base(bool runInitializer)
          {
              if (runInitializer)
              {
                  this.Initialize();
              }
          }
      
          protected void Initialize()
          {
              ...initialize...
          }
      }
      
      public class Derived : Base
      {
          // explicitly referencing the base constructor keeps
          // the default one from being invoked.
          public Derived() : base(false)
          {
             ...derived code
             this.Initialize();
          }
      }
      

      【讨论】:

        【解决方案5】:

        您必须在派生类构造函数的主体之前调用基类构造函数。

        class Derived : Base
        {
          public Derived(string someParams)
            : base("Blah " + someParams)
          {
        
          }
        
        }
        

        【讨论】:

        • 这可能是这个简单案例的最佳解决方案,但如果构造参数要复杂得多,它会很快变得丑陋。
        • 确实如此,尽管您也可以在静态方法中构造参数并将结果传递给基类构造函数。我更喜欢这种方法。或者,由于这是 .NET,因此您可以从构造函数中删除内容并在 setter 中执行,这是序列化友好的。
        【解决方案6】:

        构造函数需要注意的点:

        · 构造函数不能是“虚拟的”。

        · 他们不能被继承。

        · 构造函数按继承顺序调用。

        public Child(string a):base(a){}
        

        【讨论】:

          【解决方案7】:

          你不能。你可以先调用它:

          public Derived() : base()
          

          或者你必须使用钩子

          class Base
          {
            protected void init() { }
            public Base(string sMessage)
            {
               init();
            }
          }
          
          class Derived : Base
          {
            public Derived(string someParams)
            {
             string sMessage = "Blah " + someParams;
             init();
            }
          }
          

          【讨论】:

          • 既然 Base 构造函数应该做一些事情(可能是 sMessage 的一些事情),这段代码是如何解决他的问题的?
          • 如果你使用钩子,你需要有办法避免调用默认的基础构造函数。请参阅我的答案,通过提供不运行初始化程序的构造函数来避免这种情况。
          • @wcm:我只是展示了实现 DotnetDude 需要的操作顺序的步骤。看起来他对 C# 的理解足够好,可以从这里更改参数并返回对象以满足他的实际需求。
          • @Dinah -- 如果没有默认构造函数,这甚至无法编译。如果添加调用 init() 的默认构造函数,则 init() 会被调用两次:一次在基构造函数中,一次在派生构造函数中。如果你使用钩子实现,你需要有一个不运行它的构造函数。
          猜你喜欢
          • 2010-09-25
          • 2014-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-11
          • 2017-02-04
          • 2020-09-22
          相关资源
          最近更新 更多