如何防止具有公共派生类的抽象类在其他程序集中被继承?
我想编写如下内容:
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
无法实现它(因为它不知道 内部数据
)。 内部无参数 Base
构造函数会阻止创建任何 ExternalDerived
实例,因此没有人会实现 ExternalDerived.DoProcess
并且没有 InternalData
需要公开曝光,但编译器不知道。
我如何重写上面的代码,以便有一个抽象的 DoProcess(InternalData)
方法,并且 InternalData
类将是内部的?
I want to write something like the following:
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();
}
}
That is, Base
contains some internal logic and is not intended to be inherited by classes outside of my assembly; and Derived
is accessible from the outside.InternalData
also contains some internal logic and, as it would (and should) never be used from the outside, i also want to make it internal.
Of course the code above won't compile as the Base
should not be less accessible than Derived
. I can set the Base
to be public
, that's fine, but it leads to another problem.
If Base
is public, then there could possibly be some ExternalDerived : Base
in some other assembly. But Base.DoProcess
accepts an InternalData
as its argument, so that ExternalDerived
cannot implement it (as it doesn't know about the InternalData
).
Internal parameterless Base
constructor prevents creation of any ExternalDerived
instances, and thus nobody will implement ExternalDerived.DoProcess
and no InternalData
public exposure is needed, but the compiler doesn't know it.
How can i rewrite the code above so that there will be an abstract DoProcess(InternalData)
method and so that InternalData
class will be internal?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
从 C# 7.2 开始,就有了
private protected
访问修饰符,这意味着“仅适用于同一程序集中的派生类”。换句话说,它必须满足
internal
和protected
的条件,这与适用于internal
OR 的protected internal
不同受保护
。您可以将基类的构造函数标记为
private protected
,从而有效地防止通过程序集外部的此构造函数继承该类,同时仍允许在该程序集(以及程序集的友元)内进行继承。因此,像这样的类:
有效地密封在程序集外部,同时仍然可以在程序集内继承。
Since C# 7.2 there is
private protected
access modifier, which means "available only to derived classes in the same assembly".In other words, it must meet conditions for both
internal
ANDprotected
, unlikeprotected internal
which applies tointernal
ORprotected
.You can mark the base class' constructor as
private protected
, effectively preventing inheritance of that class through this constructor outside the assembly while still allowing inheritance within that assembly (and the assembly's friends).So, a class like this:
is effectively sealed outside the assembly, while still inheritable within the assembly.
要使
InternalData
成为内部数据,DoProcess
必须是private
或internal
(或
InternalAndProtected
,但 C# 不支持此 CLR 功能)。它不能受保护
或内部保护
。我可能还会添加一个内部抽象 void DoNotInheritFromThisClassInAnOutsideAssembly() 成员。这可以防止程序集外部的任何人从您的类继承,因为他们无法实现该成员并且会得到合理的编译器错误。但是您不能将
Base
类本身设为内部类。我会考虑重构代码,这样就没有公共基类了。可能是通过使用一些
内部
接口和组合。To make
InternalData
internal,DoProcess
must beprivate
orinternal
(or
InternalAndProtected
, but C# doesn't support this CLR feature). It can't beprotected
orprotected internal
.I'd probably also add an
internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly()
member. That prevents anybody outside the assembly from inheriting from your class, because they can't implement that member and they get a reasonable compiler error. But you can't make theBase
class itself internal.I'd consider refactoring the code, so that you have no common base class. Probably by using some
internal
interfaces and composition.闻起来你应该使用 组合而不是继承。抱歉,这是一个非常模糊的答案。我现在更多地考虑这个问题..
It smells like you should use composition instead of inheritance. sorry, this is a very vague answer. I'm thinking more about this now..
基类型必须是可访问的,否则就不可能找出它的基类型。您的
Base
直接派生自System.Object
,但是Derived
的用户如何知道这一点呢?它如何知道Base
不是从另一个公共类型派生的,并且该类型的成员应该可用?如果将
Base
中的所有内容标记为内部(类本身除外),那么您就已经阻止了其他程序集使用它执行任何有用的操作。换句话说,如果将DoProcess
设为内部,则可以防止InternalData
变为public
。是的,无可否认,如果其他类尝试调用
DoProcess
,那么您自己的程序集中可能会出现错误。不幸的是,没有“可从同一程序集中的派生类访问”访问修饰符,只有“可从派生类访问”、“可从同一程序集访问”和“可从派生类访问并可从同一程序集访问”。 (实际上,.NET 确实支持它,但 C# 不支持。)The base type must be accessible, because otherwise, it becomes impossible to figure out its base. Your
Base
derives directly fromSystem.Object
, but how does a user ofDerived
know that? How does it know thatBase
doesn't derive from another public type, and that type's members should be made available?If you mark everything in
Base
internal, except for the class itself, you've already prevented other assemblies from doing anything useful with it. In other words, if you makeDoProcess
internal, you can then preventInternalData
from becomingpublic
.Yes, admittedly this allows for bugs in your own assembly, if other classes try to call
DoProcess
. Unfortunately, there is no "accessible from derived classes in the same assembly" access modifier, only "accessible from derived classes", "accessible from the same assembly" and "accessible from derived classes and accessible from the same assembly". (Actually, .NET does support it, but C# doesn't.)将
Base
设置为public
。更改Base.DoProcess:
更改Derived.DoProcess: >
Set
Base
to bepublic
.Change Base.DoProcess:
Change Derived.DoProcess:
它实际上非常简单。您只需要派生类实现抽象内部方法即可。库外部的类将无法实现抽象方法,因此在编译时失败。
您的示例已最小化,仅包含必需品:
It is actually quite straight forward. You just require that a deriving class implement an abstract internal method. Classes outside the library won't be able to implement the abstract method, and thus fail at compile time.
Your example, minimized to just the essentials: