我想写如下内容:
internal class InternalData
{
}
public class PublicData
{
}
abstract internal class Base {
internal Base() { }
private static InternalData CreateInternalDataFromPublicData(PublicData publicData)
{
throw new NotImplementedException();
}
abstract protected void DoProcess(InternalData internalData);
public void Process(PublicData publicData)
{
InternalData internalData = CreateInternalDataFromPublicData(publicData);
DoProcess(internalData);
}
}
public sealed class Derived : Base
{
protected override void DoProcess(InternalData internalData)
{
throw new NotImplementedException();
}
}
也就是说,Base
包含一些内部逻辑,不能由程序集外部的类继承;并且Derived
可从外部访问。InternalData
还包含一些内部逻辑,并且从不(从不应该从外部使用),我也想使其内部化。
当然,上面的代码不会编译,因为Base
的访问权限不应比Derived
少。我可以将Base
设置为public
,这很好,但这会导致另一个问题。如果Base
是公开的,则其他某个程序集中可能会有ExternalDerived : Base
。但是Base.DoProcess
接受InternalData
作为其参数,因此ExternalDerived
无法实现它(因为它不知道InternalData
)。内部无参数Base
构造函数阻止创建任何ExternalDerived
实例,因此没有人将实现ExternalDerived.DoProcess
,并且不需要InternalData
公共公开,但编译器不知道。
我该如何重写上面的代码,以便有一个抽象的DoProcess(InternalData)
方法,并使InternalData
类在内部?
将Base
设置为public
。
public abstract class Base {...
更改Base.DoProcess:
protected virtual void DoProcess<T>(T internalData)
{
if (!(internalData is InternalData))
{
throw new ArgumentOutOfRangeException("internalData");
}
}
Change Derived.DoProcess:
protected override void DoProcess<T>(T internalData)
{
base.DoProcess(internalData);
// Other operations
}
要使InternalData
为内部,DoProcess
必须为private
或internal
(或InternalAndProtected
,但C#不支持此CLR功能)。不能是protected
或protected internal
。
internal abstract DoProcess(InternalData internalData);
我可能还会添加一个internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly()
成员。这样可以防止程序集外部的任何人从您的类继承,因为他们无法实现该成员,并且会遇到合理的编译器错误。但是您不能将Base
类本身设置为内部。
我会考虑重构代码,以便您没有通用的基类。可能通过使用某些internal
接口和组成。
闻起来好像您应该使用composition instead of inheritance。抱歉,这是一个非常模糊的答案。我现在正在考虑更多。.
基类型必须是可访问的,因为否则,将无法弄清其基。您的Base
直接来自System.Object
,但是Derived
的用户如何知道呢?它如何知道Base
不是从另一个公共类型派生的,并且应该使该类型的成员可用?
如果您在Base
内部标记了所有内容,除了类本身,则您已经阻止其他程序集对其进行任何有用的操作。换句话说,如果将DoProcess
设为内部,则可以防止InternalData
成为public
。
是的,如果其他类尝试调用DoProcess
,则这会允许您自己的程序集中存在错误。不幸的是,没有“从同一程序集的派生类可访问”访问修饰符,只有“可从派生类访问”,“可从同一程序集访问”和“可从派生类访问且可从同一程序集访问”。 (实际上,.NET确实支持它,但是C#不支持。)
自C#7.2起,存在private protected
访问修饰符,这意味着“仅可用于同一程序集中的派生类”。]
换句话说,它必须同时满足internal
和protected
的条件,与protected internal
适用于internal
或protected
的情况不同。
您可以将基类的构造函数标记为private protected
,从而有效地防止通过此类构造函数在程序集外部继承该类,同时仍然允许该程序集(以及程序集的朋友)内的继承。
所以,这样的类:
public abstract BaseClass { private protected BaseClass() {} }
在程序集外部有效密封,但仍可在程序集内部继承。
实际上非常简单。您只需要派生类实现抽象的内部方法即可。库外部的类将无法实现abstract方法,因此在编译时会失败。