寻找一种隐藏类的方法基类
我正在构建一个库,其中有如下模式:
public class Foo : Foo_Impl
{
}
public class Foo_Impl
{
}
我不希望其他开发人员意外使用 Foo_Impl 类。我可以使用哪些选项来隐藏此内容?我还想将它隐藏在定义它的同一程序集中的其他类中。理想情况下,我很乐意这样做:
public class Foo : Foo_Impl
{
private class Foo_Impl
{
}
}
但由于多种原因,这不起作用。
I'm building a library where I've got a pattern like the following:
public class Foo : Foo_Impl
{
}
public class Foo_Impl
{
}
I don't want other developers to accidentally use the Foo_Impl class. What options are available to me to hide this? I'd also like to hide it from other classes in the same assembly it's defined in. Ideally I'd have loved to do:
public class Foo : Foo_Impl
{
private class Foo_Impl
{
}
}
But that doesn't work for a variety of reasons.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我还没有看到这个建议,所以我想我应该添加 0.02 美元。
使用组合而不是继承怎么样? Foo_Impl 的实例可以由 Foo 维护,并且永远不会对外界可见(因为 Foo_impl 对于程序集来说是私有的)。根据需要,可以通过接口将调用传递给 Foo_Impl 函数。您可以获得相同的功能,并且没有任何设计难题。
至于“对程序集中的其他类隐藏它”,如果您确实认为合适,则可以将其设为嵌套类。
I haven't seen this suggested yet, so I thought I would add my $.02.
How about using composition instead of inheritance? An instance of Foo_Impl can be maintained by Foo and will never be visible to the outside world (because Foo_impl will be private to the assembly). Calls can be passed through the interface to Foo_Impl functions as needed. You get the same functionality and none of the design headaches.
As far as "hiding it from other classes in the assembly", you could make it a nested class if you really felt that was appropriate.
使 Foo_Impl 成为一个抽象类。这不会阻止其他开发人员从中派生,但将无法直接创建
Foo_Impl
实例 - 需要通过创建派生对象来实例化它,例如Foo
。-
根据 Thomas Levesque 的建议,您还可以选择将抽象构造函数设置为内部:
这将防止开发人员从程序集外部继承
Foo_Impl
。Make
Foo_Impl
an abstract class. This won't stop other developers from deriving from it, but it will make it impossible to create an instance ofFoo_Impl
directly - it will need to be instantiated by creating a derived object, such asFoo
.-
Per Thomas Levesque's suggestion, you also have the option of making the abstract constructor internal:
This will prevent developers from inheriting from
Foo_Impl
from outside the assembly.没有办法完全隐藏它。如果 Foo 将是公共的,那么它的基类也必须是公共的。但是,您可以通过保护构造函数来阻止其他开发人员创建 Foo_Impl 实例。这样构造函数只能从派生类中使用。
如果您不希望人们能够创建自己的从
Foo_Impl
派生的类,请将构造函数设为内部There is no way to completely hide it. If
Foo
is going to be public, its base class has to be public too. However, you can prevent other developers from creating an instance ofFoo_Impl
, by making the constructor protected. That way the constructor can only be used from derived classes.If you don't want people to be able to create their own classes derived from
Foo_Impl
, make the constructor internal您拥有的选项是:
使 Foo_Impl 抽象。开发者将无法直接实例化 Foo_Impl;他们必须声明一个 Foo。不过,Foo_Impl 仍然可以用作方法参数或泛型类型参数,开发人员可以从 Foo_Impl 派生自己的类。
将 Foo_Impl 设为内部,并将其和 Foo 与您想要隐藏 Foo_Impl 的任何其他类放在单独的库中。在该程序集之外工作的开发人员将无法看到 Foo_Impl。但是,如果开发人员在运行时具有足够的 CAS 权限,则他们可能能够反映该类型并实例化该类型,并且任何有权访问程序集源代码的开发人员都可以在该程序集中新建一个 Foo_Impl。
使 Foo_Impl 的所有构造函数受保护或内部。受保护的构造函数只能由派生类访问,而内部构造函数只能从同一程序集中访问。无论哪种方式,Foo_Impl 都不能由外部人员实例化。但是,开发人员仍然可以将该类用作参数或泛型类型。
使用 [Obsolete] 属性将 Foo_Impl 的构造函数或整个类标记为已过时,指定使用此类应触发错误。这是一种 hack,但您既可以防止编译“错误”代码,又可以使用属性的 Message 参数来指定应该使用什么。然而,要小心你的装饰;如果你装饰整个类,我认为编译器不会让你对这个类做任何事情,包括继承它。装饰构造函数应该会阻止大多数编码人员。
The options you have are:
Make Foo_Impl abstract. Developers will not be able to instantiate a Foo_Impl directly; they must declare a Foo. However, Foo_Impl can still be used as a method parameter or generic type parameter, and developers can derive their own classes from Foo_Impl.
Make Foo_Impl internal, and place both it and Foo in a seperate library from any other class you want to hide Foo_Impl from. Developers working outside that assembly will not be able to see Foo_Impl. However, developers may be able to reflect the type and instantiate one if they have sufficient CAS permissions in the runtime, and any developer with access to your assembly's source can new up a Foo_Impl within that assembly.
Make all constructors of Foo_Impl protected or internal. Protected constructors can only be accessed by derived classes, while internal constructors can only be accessed from within the same assembly. Either way, a Foo_Impl cannot be instantiated by an outsider. However, developers can still use the class as a parameter or generic type.
Mark Foo_Impl's constructors, or the whole class, as Obsolete using the [Obsolete] attribute, specifying that use of this class should trigger an error. It's kind of a hack, but you can both prevent compilation of "wrong" code, and use the Message parameter of the attribute to specify what SHOULD be used. However, take care what you decorate; if you decorate the entire class, I do not think the compiler will let you do ANYTHING with the class, including inherit from it. Decorating the constructors ought to stop most coders.
这可能听起来很愚蠢,但有一个非常简单的解决方案:记录正确的用法。如果 Foo_Impl 不应该被实例化,那么向类中添加一条注释来说明这一点。也将其包含在有关该类的任何其他文档中。
即使您在此处实现了其他解决方案之一,您也可以(并且应该)执行此操作。
This might sound silly, but there's a very simple solution: document the correct usage. If Foo_Impl shouldn't be instantiated, then add a comment to the class saying so. Include it in any other documentation about the class, as well.
You can (and should) do this even if you implement one of the other solutions here.
abstract 关键字可能最适合您的场景。请记住,如果您提供一个程序集 (dll),希望人们利用特定的功能,则可以通过接口实现黑盒范例。如果您提供要使用的接口并在内部实现该接口,则您的程序集可以提供接口引用,而无需移交对实例化类本身的引用。所有开发人员都知道您在接口定义中定义的属性和方法。这在插件架构中非常常见。
The abstract keyword is probably the most applicable to your scenario. Bear in mind that if you are providing an assembly (dll) that you want people to take advantage of a particular bit of functionality, you can implement the black box paradigm via Interfaces. If you provide the interface to be used and internally implement the interface, your assembly can provide the interface reference without handing over a reference to the instantiated class itself. All the developers would know are the properties and methods you've defined in the interface definition. This is highly common in plugin architectures.
好吧,我想我已经解决了这个谜题。您分两部分实现 Foo_Impl。
一种是 publicpartial class Foo_Impl {} 实现,它基本上是一个空类,什么都不做,所以它在任何意义上都不可用。
另一个是作为
Foo:Foo_Impl
类的私有分部类 Foo_Impl{}
成员实现的。那就是你放置所有只能由 Foo 本身使用的秘密功能的地方。任何类都可以从 Foo_Impl 的公共部分继承,但不能使用仅通过其私有 Foo_Impl 成员才能使用 Foo 的任何私有功能。使用class Voyeur:Foo_Impl
示例来说明每个主体都可以继承,但只有Foo可以实例化和使用它。Voyeur
无法窥视 Foo_Impl 来一睹其有用的私有部分;)。Ok, I think I have solved the riddle. You implement Foo_Impl in two partial parts.
One is
public partial class Foo_Impl {}
implementation which is basically an empty class doing nothing, so it will not be usable in any sense.The other is implemented as a
private partial class Foo_Impl{}
member of theFoo:Foo_Impl
class. Thats where you put all your secret functionality that can only be used by Foo itself. Any class can inherit from the public partial part ofFoo_Impl
but cannot use any of the private functionality only available to Foo through its private Foo_Impl memeber. An exampleclass Voyeur:Foo_Impl
is used to illustrate that every body can inherit but only Foo can instantiate and use it.Voyeur
cannot peep into Foo_Impl to get a glimpse of its useful private parts ;) .