【问题标题】:How can I prevent a base constructor from being called by an inheritor in C#?如何防止 C# 中的继承者调用基本构造函数?
【发布时间】:2010-09-14 15:06:57
【问题描述】:

我有一个(写得很糟糕的)基类,我想将它包装在一个代理对象中。基类类似于以下内容:

public class BaseClass : SomeOtherBase 
{
   public BaseClass() {}

   public BaseClass(int someValue) {}

   //...more code, not important here
}

而且,我的代理类似于:

public BaseClassProxy : BaseClass
{
  public BaseClassProxy(bool fakeOut){}
}

如果没有“fakeOut”构造函数,则预计会调用基本构造函数。但是,有了它,我希望它不会被调用。无论哪种方式,我要么需要一种不调用任何基类构造函数的方式,要么需要某种其他方式来有效地代理这个(邪恶的)类。

【问题讨论】:

  • public BaseClass() { if ( GetType() != typeof(BaseClass) ) return; ... }

标签: c# oop inheritance proxy constructor


【解决方案1】:

我的另一个简单解决方案:

class parent
{
    public parent()
    {
        //code for all children

        if (this.GetType() == typeof(child1))
        {
            //code only for objects of class "child1"
        }
        else
        {
            //code for objects of other child classes
        }
    }
}

class child1 : parent
{
    public child1()
    {}
}

// class child2: parent ... child3 : parent ... e.t.c

【讨论】:

    【解决方案2】:

    这是我解决问题的方法

    using System;
    
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine(new Child().Test);
        }
    
        public class Child : Parent {
            public Child() : base(false) {
                //No Parent Constructor called
            }
        }
        public class Parent {
            public int Test {get;set;}
            public Parent()
            {
                Test = 5;
            }
            public Parent(bool NoBase){
                //Don't do anything
            }
        }
    }
    

    一个简单优雅的解决方案。您可以根据需要进行更改。

    【讨论】:

      【解决方案3】:

      可以在不调用无参数构造函数的情况下创建对象(参见上面的答案)。但是我使用这样的代码来创建一个基类和一个继承类,我可以在其中选择是否执行基类的init。

      public class MyClass_Base
      {
          public MyClass_Base() 
          {
              /// Don't call the InitClass() when the object is inherited
              /// !!! CAUTION: The inherited constructor must call InitClass() itself when init is needed !!!
              if (this.GetType().IsSubclassOf(typeof(MyClass_Base)) == false)
              {
                  this.InitClass();
              }
          }
      
          protected void InitClass()
          {
              // The init stuff
          }
      }
      
      
      public class MyClass : MyClass_Base
      {
          public MyClass(bool callBaseClassInit)
          {
              if(callBaseClassInit == true)
                  base.InitClass();
          }
      }
      

      【讨论】:

        【解决方案4】:

        好吧,对于一个类继承另一个类的构造函数的问题,这是一个丑陋的解决方案,我不想让它们中的一些工作。我希望避免使用这在我的课堂上,但这里是:

        这是我的类构造函数:

        public MyClass();
        {
           throw new Exception("Error: Must call constructor with parameters.");
        }
        

        好的,现在你被警告说它很丑。请不要抱怨!

        我想至少从我的主构造函数中强制最小参数,而不允许继承的没有参数的基本构造函数。

        我也相信,如果你创建一个构造函数并且不把 : base() 放在它之后,它就不会调用基类构造函数。如果你为所有的构造函数创建构造函数在基类中并在主类中为它们提供相同的确切参数,它不会通过。但是如果基类中有很多构造函数,这可能会很乏味!

        【讨论】:

          【解决方案5】:

          有一种方法可以在不调用任何实例构造函数的情况下创建对象。

          在您继续之前,请确定您想以这种方式进行操作。 99% 的情况下这是错误的解决方案。

          这就是你的做法:

          FormatterServices.GetUninitializedObject(typeof(MyClass));
          

          调用它来代替对象的构造函数。它将创建并返回一个实例,而无需调用任何构造函数或字段初始值设定项。

          当您在 WCF 中反序列化一个对象时,它会使用此方法来创建该对象。发生这种情况时,构造函数甚至字段初始值设定项都不会运行。

          【讨论】:

          • 这太疯狂了。我的整个世界都颠倒了!
          • Welp,这解决了我的问题!在继承类上运行单元测试时,尽量避免父对象的构造函数的 DB 调用。
          • FormatterServices.GetUninitializedObject(typeof(MyClass));然而,仍然会调用静态构造函数。
          • @PaulSuart,说得好。我已经更新了我的答案以反映这一点。
          • 救命稻草。正是我想要的。
          【解决方案6】:

          至少需要调用 1 个 ctor。我看到的唯一解决方法是遏制。将类放在内部或引用其他类。

          【讨论】:

          • 这是获得最多结果的路径。谢谢!
          • 我可以补充一下,使用包含是实现代理模式的最典型方式。您通常显式地实例化代理,并使其实现与代理对象相同的接口:MyInterface myProxy = new MyProxiedClass(new MyClass());
          【解决方案7】:

          构造函数本质上是公共的。不要使用构造函数并使用另一个构造函数并将其设为私有。因此您将创建一个没有参数的实例并调用该函数来构造您的对象实例。

          【讨论】:

            【解决方案8】:

            我最终做了这样的事情:

            public class BaseClassProxy : BaseClass 
            {
               public BaseClass BaseClass { get; private set; }
            
               public virtual int MethodINeedToOverride(){}
               public virtual string PropertyINeedToOverride() { get; protected set; }
            }
            

            这让我了解了基类的一些不良做法。

            【讨论】:

            • 隐式默认构造函数仍然调用BaseClass的无参数构造函数。
            【解决方案9】:

            我担心不调用构造函数不是选项。

            【讨论】:

              【解决方案10】:

              如果您想要调用两个基类构造函数中的任何一个,则无法做到。

              C# 类构造函数必须调用基类构造函数。如果您不明确调用一个,则 base( ) 是隐含的。在你的例子中,如果你没有指定调用哪个基类构造函数,则同:

              public BaseClassProxy : BaseClass
              {
                  public BaseClassProxy() : base() { }
              }
              

              如果您更喜欢使用其他基类构造函数,可以使用:

              public BaseClassProxy : BaseClass
              {
                  public BaseClassProxy() : base(someIntValue) { }
              }
              

              无论哪种方式,都会显式或隐式调用两个中的一个

              【讨论】:

                【解决方案11】:

                我不相信你可以绕过调用构造函数。但你可以这样做:

                public class BaseClass : SomeOtherBase 
                {
                   public BaseClass() {}
                
                   protected virtual void Setup()
                   {
                   }
                }
                
                public BaseClassProxy : BaseClass
                {
                   bool _fakeOut;
                   protected BaseClassProxy(bool fakeOut)
                   {
                        _fakeOut = fakeOut;
                        Setup();
                   }
                
                   public override void Setup()
                   {
                       if(_fakeOut)
                       {
                            base.Setup();
                       }
                       //Your other constructor code
                   }
                } 
                

                【讨论】:

                  【解决方案12】:

                  当您创建 BaseClassProxy 对象时,它需要创建其基类的实例,因此您需要调用基类构造函数,您可以选择调用哪个,例如:

                  public BaseClassProxy (bool fakeOut) : base (10) {}
                  

                  调用第二个构造函数而不是第一个构造函数

                  【讨论】:

                    【解决方案13】:

                    如果没有显式调用基类中的任何构造函数,则将隐式调用无参数构造函数。没有办法,你不能在没有构造函数的情况下实例化一个类。

                    【讨论】:

                    • 其实,如果你看了我下面的评论,是有办法的,虽然在大多数情况下我不会推荐它。
                    • 这个答案是完全错误的。尤其是考虑到其他答案。
                    猜你喜欢
                    • 2015-11-16
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-03-31
                    • 1970-01-01
                    • 2014-07-25
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多