内部抽象类:如何隐藏程序集外的用法?
我有一个常见的程序集/项目有一个抽象的基类,然后我想公开其他程序集的几个派生类。
我不想让抽象基类在Intellisense中的其他程序集中出现,所以我想我会把它放在internal
,但是我得到这个错误:
不一致的可访问性:基类“设置”比类“IrcSettings”更难以访问….
我真的不明白这一点。 我不得不使抽象的Settings
类public
,因此在这个程序集之外是可见的。
我怎样才能让这个classinternal
呢?
据我所知,你希望你的抽象类只能被其他类在同一个程序集中实现(例如它是内部的),但派生类可以是公共的。
这样做的方法是使抽象基类公开,但给它一个内部的默认构造函数:
public abstract class MyClass { internal MyClass() { } }
这将允许MyClass(及其成员)对程序集外的类可见和可用,但程序集外部的类不能从它inheritance(将得到编译错误)。
编辑:如果外部程序集可以看到的类从MyClassinheritance,则不能阻止MyClass被看到 – 例如,显示在Intellisense中。 但是,您可以通过以下方式防止它们被使用 。
抽象基类必须是公共的,因为整个类的inheritance规范必须是可见的。 这确保了多态性的工作和有效; 但是所有基类的成员都可以是内部的(包括构造函数),因此不能在你的程序集之外使用
对于你想要达到的目标而言,实际上没有什么好处,但是你实际上想要达到的目标与此类似。
把你的抽象基类放在1个程序集里面, 在该Assembly的AssemblyInfo中,需要添加
[assembly:InternalsVisibleTo("cs_friend_assemblies_2")]
然后在另一个大会,你有所有你想公开的课程。 请注意,您仍然可以通过intellisense访问cs_friend_assemblies_2中的任何代码的基类,或者任何您命名您的程序集的地方,而不是任何其他地方。
您不能同时使其他程序集可用于inheritance,但也是私有的,所以对其他用户不可见。 你可以使这个类成为内部的,并使用[InternalsVisibleTo]
属性将它暴露给一个特定的程序集(如果它是一个朋友程序集),但是我不认为这是你想要的。
如果你想让代码(派生类除外)能够实例化你的基类,你可以给它一个受保护的构造函数:
abstract class MyBaseClass { protected MyBaseClass() { ... } // only inheritors can access this... }
您可以使用EditorBrowsable
属性从Intellisense中隐藏类成员:
abstract class MyBaseClass { [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void SomeMethodToBeHidden() { } }
应该指出的是,有些人报告IDE的问题并不总是尊重这个属性。
就我而言,这是一个没有问题的问题。 注意:
public abstract class Foo { public void virtual Bar() { // default implementation } } public class NormalFoo : Foo { } public class SpecialFoo : Foo { public override void Bar() { // special implementation } } var foolist = new List<Foo>(); foolist.Add( new NormalFoo() ); foolist.Add( new SpecialFoo() ); foreach (var f in foolist) { f.Bar(); }
如果没有多态性,上述方法根本无法工作 – 可以通过通用接口抽象基类来引用不同派生类的实例。 你想要做的就是把它拿走,削弱你class级的可用性。 我不认为你应该继续走下去。
其他程序集是否会inheritance自抽象基类或任何inheritance自抽象基类的公共类?
如果是这样,你必须公开抽象基类。 只是让你不想在程序集内部看到的方法。
如果没有,也许接口可以帮助? 定义公共接口,使公共类实现它们,并提供工厂来获取实例。 这样,intellisense在程序集外看到的唯一东西就是界面。
这有帮助吗?
解决此限制的一种方法是使用组合而不是inheritance(还有其他 很好的理由也可以)。 例如,而不是:
internal abstract class MyBase { public virtual void F() {} public void G() {} } public class MyClass : MyBase // error; inconsistent accessibility { public override void F() { base.F(); /* ... */ } }
做这个:
public interface IMyBase { void F(); } internal sealed class MyBase2 : IMyBase { public void F() {} public void G() {} } public sealed class MyClass2 : IMyBase { private readonly MyBase2 _decorated = new MyBase2(); public void F() { _decorated.F(); /* ... */ } public void G() { _decorated.G(); } }
如果公众不需要知道它,而且你的内部也不需要,你可以完全省略IMyBase
接口。