【问题标题】:What's the difference between an abstract class, and a class with only protected constructors? (.NET)抽象类和只有受保护构造函数的类有什么区别? (。网)
【发布时间】:2011-01-13 16:07:27
【问题描述】:

抽象类和只有受保护构造函数的类之间有什么区别?它们似乎与我非常相似,因为你不能实例化任何一个。

编辑:

如何在派生类中创建一个实例,其中基类具有受保护的构造函数?例如:

public class ProtectedConstructor
{
    protected ProtectedConstructor()
    {

    }

    public static ProtectedConstructor GetInstance()
    {
        return new ProtectedConstructor(); // this is fine
    }
}

public class DerivedClass : ProtectedConstructor
{

    public void createInstance()
    {
        ProtectedConstructor p = new ProtectedConstructor(); // doesn't compile
    }

    public static ProtectedConstructor getInstance()
    {
        return new ProtectedConstructor(); // doesn't compile

    }
}

【问题讨论】:

  • 为什么这个维基被标记?这里有明确、明确的答案……
  • 我编辑了我的答案以添加对此的建议。
  • @Reed 对不起,我的错。我担心它过于开放。

标签: c# constructor abstract-class protected


【解决方案1】:

可以从类本身中实例化具有受保护构造函数的类 - 在静态构造函数或静态方法中。这可用于实现单例或工厂类型的东西。

一个抽象类根本无法实例化 - 目的是一个或多个子类将完成实现,这些类将被实例化

编辑:

如果您调用ProtectedConstructor.GetInstance(); 而不是new ProtectedConstructor();,它会起作用。也许不能这样调用受保护的构造函数?但是受保护的方法当然可以。

Here 是一篇关于该主题的有趣文章。

【讨论】:

  • 您还可以从子类或通过反射实例化该类。
  • 没错,但在这种情况下,将它们标记为私有会更有意义。
  • 但在这种情况下 base() 将无法在派生类中工作。将它们标记为私有或受保护会导致不同的行为。
【解决方案2】:

大多数时候,几乎没有实际区别,因为两者都只能通过子类生成。

但是,标记类 abstract 有两个好处:

  1. 使用受保护的构造函数,仍然可以通过两种方式创建类的实例。您可以将Activator.CreateInstance 与BindingFlags.NonPublic 一起使用,也可以使用类(或子类)中定义的工厂方法来创建类的实例。但是,不能创建标记为抽象的类。

  2. 通过标记课程abstract,您的意图更加明确。就个人而言,我认为这是最有说服力的理由。

【讨论】:

    【解决方案3】:

    从外部,黑盒的角度来看,是的,它们是相似的,因为你不能实例化任何一个。但是,您可以永远实例化一个抽象类,在这种情况下,您可以从类本身或从继承者构造一个仅具有受保护构造函数的类。

    【讨论】:

    • 你会如何从继承人那里做到这一点?我已经编辑了上面的问题。
    • 受保护的构造函数只能由继承类的构造函数调用(即 public DerivedClass() : base() 将起作用),不能从继承类中的方法调用。我不确定其中的原因。
    【解决方案4】:

    一个抽象类可以有抽象方法;仅包含方法签名但不包含子类必须实现的主体的方法。

    说真的,还没有人提到过?

    【讨论】:

      【解决方案5】:

      您的示例存在缺陷,因为在 getInstance 案例中,因为您构造了 ProtectedConstructor 类并期望将其向下转换为 DerivedClass。相反,您需要一个稍微更完整的实现,其中派生类有一个构造函数:

      public class ProtectedConstructor
      {
          protected ProtectedConstructor(string arg)
          {
              // do something with arg
          }
      
          public static ProtectedConstructor GetInstance()
          {
              return new ProtectedConstructor("test"); 
          }
      } 
      
      public class DerivedClass : ProtectedConstructor
      {
          protected DerivedClass(string arg) : base(arg)
          {
          }
      
          public void createInstance()
          {
              DerivedClass p = new DerivedClass("test"); 
          }
      
          public static DerivedClass getInstance()
          {
              return new DerivedClass("test"); 
          }
      }
      

      尽管抽象类的主要区别在于定义子类必须实现但您不想为其提供默认实现的抽象方法。例如,假设您有某种具有 Run 方法的 Thread 类。您要确保对 Run 的每次调用首先设置一些日志记录,然后执行线程的实际工作,然后停止日志记录。你可以像这样写一个抽象的 Thread 类:

      public abstract Thread
      {
          protected Thread()
          {
          }
      
          public void Run()
          {
              LogStart();
              DoRun();
              LogEnd();
          }
      
          protected abstract DoRun();
      
          private void LogStart()
          {
               Console.Write("Starting Thread Run");
          }
      
          private void LogEnd()
          {
               Console.Write("Ending Thread Run");
          }
      }
      
      
      public class HelloWorldThread : Thread
      {
          public HelloWorldThread()
          {
          }
      
          protected override DoRun()
          {
              Console.Write("Hello World");
          }
      }
      

      【讨论】:

      • @Jon 对不起,我不是故意这么沮丧的。我已经编辑了这个问题。我想说的是你不能实例化 ProtectedConstructor,即使在派生类中也是如此。
      【解决方案6】:

      我没有看到其他人提到的另一件要考虑的事情是,您的代码将来可能会被维护。如果维护者为一个类添加了一个公共构造函数,那么它就可以被实例化。这可能会破坏您的设计,因此您应该阻止它(或设计以适应它)。

      为防止其他人进行此类更改,您可以注释您的代码。或者,正如其他人所说,使用“抽象”来明确记录您的意图。

      【讨论】:

        【解决方案7】:

        嗯,想到的第一个区别是抽象类不能被实例化,但是具有受保护构造函数的类可以被实例化并抛出另一个公共方法。

        这方面的一个常见示例可能类似于单例模式:http://en.wikipedia.org/wiki/Singleton_pattern

        【讨论】:

          【解决方案8】:

          如果你从另一个抽象类继承了一个抽象类,你不必满足抽象方法,但是你可以使用一个带有受保护的ctor的普通类。例子

          public abstract class Parent { protected abstract void AMethod(); } public abstract class Child: Parent { // does not implement AMethod, and that's ok } public class Child2: Parent { // does not implement AMethod, and that will cause a compile error }

          【讨论】:

            【解决方案9】:

            如果您的意图是只允许静态使用该类(即不将其用作纯基类),那么您应该改用 static 关键字; CLR 将阻止通过包括反射 (AFAIK) 在内的任何方法创建类的实例。

            【讨论】:

              猜你喜欢
              • 2011-05-30
              • 2010-11-08
              • 2015-09-26
              • 2014-12-23
              • 2019-11-18
              • 2013-11-13
              • 2015-10-25
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多