我想写下面的内容:
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
类在内部?
答案 0 :(得分:4)
要使InternalData
为内部DoProcess
,private
必须为internal
或InternalAndProtected
(或protected
,但C#不支持此CLR功能)。它不能是protected internal
或internal abstract DoProcess(InternalData internalData);
。
internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly()
我可能还会添加Base
成员。这可以防止程序集之外的任何人从您的类继承,因为他们无法实现该成员并且他们得到合理的编译器错误。但是你不能让internal
类本身在内部。
我会考虑重构代码,这样你就没有共同的基类。可能通过使用一些{{1}}接口和组合。
答案 1 :(得分:1)
闻起来应该使用composition instead of inheritance。对不起,这是一个非常含糊的答案。我现在正在考虑这个问题..
答案 2 :(得分:1)
基本类型必须是可访问的,否则,无法找出其基础。您的Base
直接来自System.Object
,但Derived
的用户如何知道?它是如何知道Base
不是从其他公共类型派生出来的,那个类型的成员应该可用?
如果你在Base
内部标记了所有内容,除了类本身,你已经阻止了其他程序集对它做任何有用的事情。换句话说,如果您将DoProcess
设为内部,则可以阻止InternalData
成为public
。
是的,诚然,如果其他类试图调用DoProcess
,这会在您自己的程序集中出现错误。遗憾的是,没有“可从同一程序集中的派生类访问”访问修饰符,只能“从派生类访问”,“可从同一程序集访问”和“可从派生类访问并可从同一程序集访问”。 (实际上,.NET确实支持它,但C#不支持它。)
答案 3 :(得分:0)
将Base
设为public
。
public abstract class Base {...
更改Base.DoProcess:
protected virtual void DoProcess<T>(T internalData)
{
if (!(internalData is InternalData))
{
throw new ArgumentOutOfRangeException("internalData");
}
}
更改Derived.DoProcess:
protected override void DoProcess<T>(T internalData)
{
base.DoProcess(internalData);
// Other operations
}
答案 4 :(得分:0)
自C#7.2起,存在private protected
访问修饰符,这意味着“仅适用于同一程序集中的派生类”。
换句话说,它必须同时满足internal
和protected
的条件,与protected internal
适用于internal
或protected
的情况不同。
您可以将基类的构造函数标记为private protected
,从而有效地防止在程序集外部通过该构造函数继承该类,同时仍然允许该程序集(以及程序集的朋友)内的继承。
因此,这样的类:
public abstract BaseClass
{
private protected BaseClass() {}
}
在程序集外部有效密封,同时仍可在程序集内部继承。
答案 5 :(得分:-2)
实际上很直接。您只需要派生类实现抽象内部方法。库外的类将无法实现抽象方法,因此在编译时失败。
您的示例,最小化到基本要素:
abstract internal class Base {
internal protected abstract void DoProcess();
public void Process() {
DoProcess();
}
}
public sealed class Derived : Base {
internal protected override void DoProcess() {
throw new NotImplementedException();
}
}