在抽象类中,内部抽象方法的目的是什么?

12

抽象类中的内部抽象方法有什么用途? 为什么会将抽象方法设置为抽象类的内部方法?如果我们想要将抽象类限制在程序集内部,为什么不直接将其声明为内部抽象类呢?可能还有其他的逻辑原因。

3个回答

18

在一个public的抽象类中添加internal成员会使得这个抽象类无法在声明它的程序集之外继承。但是该抽象类本身以及所有派生类仍然可以在声明程序集之外被使用(因为类型是public的)。

假设你有一个抽象类:

public abstract AMyClass
{
    public string DoSomething()
    {
        return DoSomethingInternal();
    }

    internal abstract string DoSomethingInternal();
}

还有另一个公共类继承它,在同一程序集中声明。

public sealed MyClass : AMyClass
{
    internal override string DoSomethingInternal()
    {
        return "Hey from MyClass!";
    }
}

您仍然可以在不同的程序集中创建MyClass实例,但是您将无法实现派生自AMyClass的自定义类,因为您将无法实现抽象的DoSomethingInternal方法。


谢谢Marcin的回复,但您能否请解释一下这些代码行... 但是类本身以及所有派生类仍然可以在声明程序集之外使用(因为类型是公共的)。 - Arun Bisht
1
我简直不敢相信,在编程超过20年后,我居然不知道这个。这真的帮助我解决了一个困难的问题。 - Sentinel
我有一个.NET Framework 4.8项目,其中包含一个空类,该类派生自public abstract class ServerProtocol (System.Web.Services.Protocols.ServerProtocol),并且该类具有internal abstract成员,但是在VS2019中编译正常,并且ILSpy显示它存在。但是当我尝试在LinqPad 5中实例化它时,我只会得到一个运行时的TypeLoadException。而旧版本的VS确实会阻止编译。这很奇怪... - Dai

7

internal关键字是类型和类型成员的访问修饰符。 内部类型或成员仅在同一程序集中的文件中可访问,例如:

public class BaseClass 
{
    // Only accessible within the same assembly
    internal static int x = 0;
}

现在在你的情况下,类似于以下内容:
public abstract BaseClass
{
   internal abstract void Print();
}

现在,在这种情况下,所有与BaseClass在同一个程序集中的类都可以覆盖BaseClass的Print方法。但是程序集外的类只能覆盖公共成员,例如:
 public abstract BaseClass
 {
    internal abstract void Print();
    public abstract void Hello();
 }

在BaseClass程序集之外的类将无法使用此类,因为其中一个成员是internal。 解决方案是在与BaseClass相同程序集中创建子类,并将该类用于程序集外部。

我建议您从@john skeet的《深入C#》中阅读有关C#访问修饰符概念的内容。


谢谢Mukund,但是将抽象方法设置为internal后,我无法在程序集外派生该抽象类。那么,我该如何重写它的hello方法呢? - Arun Bisht
命名空间 ClassLibrary1 { public abstract class Class1 { internal abstract void show(); public abstract void hide();
}
}我无法在程序集外派生此类。出现错误... 'ConsoleApplication1.Program' 未实现继承的抽象成员 'ClassLibrary1.Class1.show()'。
- Arun Bisht
@ArunBisht 请看一下我的回答,我认为它回答了你的问题。 - Rohit
好的,没问题Mukund,如果内部抽象类限制了它在程序集外的使用,那么为什么我们不直接将抽象类设为internal呢? - Arun Bisht
请查看这个答案。https://dev59.com/-nE95IYBdhLWcg3wdtmj - Mukund
显示剩余13条评论

2

想象一下你的项目中有一段代码

假设它是一个控制台应用程序,我们称之为ConsoleApplication1

      namespace ConsoleApplication1
      {
           class Program
           {
              static void Main(string[] args)
              {}

            }

          public abstract class MyAbsClass
          {
              public string DoSomething()
              {
                 return DoSomethingInternal();

              }

           internal abstract string DoSomethingInternal();

           public abstract string DoSomethingExternal();

          }

          public  class MyClass:MyAbsClass
          {
                 internal override string DoSomethingInternal(){}                   
                 public override string DoSomethingExternal(){}

          }
       }

现在假设您有另一个控制台应用程序(称为ConsoleApplication2),您需要构建您的ConsoleApplication1并添加对其的引用。

  using ConsoleApplication1;

  namespace ConsoleApplication2
  {
     class Program
     {
         static void Main(string[] args)
         {
         }
     }
class NewClass : MyAbsClass
{

    public override string DoSomethingExternal()
    {
        throw new NotImplementedException();
    }
  }
 }

现在当你构建这个时会出现错误:Error 1 'ConsoleApplication2.NewClass' does not implement inherited abstract member 'ConsoleApplication1.MyAbsClass.DoSomethingInternal() 为什么会出现这个错误?因为编译器告诉你,当你将成员声明为internal时,与其在同一程序集中的类(即ConsoleApplication1)可以访问它。所以无论你在ConsoleApplication2中创建多少个类,你都无法访问它,因为它被声明为internal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接