2009-08-07 8 views
41

У меня есть общая сборка/проект, который имеет абстрактный базовый класс, а затем несколько производных классов, которые я хочу публиковать в других сборках.Внутренний абстрактный класс: как скрыть использование вне сборки?

Я не хочу, абстрактный базовый класс, чтобы показать в этих других сборок в Intellisense, поэтому я думал, что сделать это internal, но я получаю эту ошибку:

Inconsistent accessibility: base class 'Settings' is less accessible than class 'IrcSettings' ....

я не делаю действительно получить это. Я вынужден сделать реферат Settings класс public и таким образом виден вне этой сборки.

Как я могу сделать этот класс internal?

+0

Просто небольшая точка, вы можете иметь интерфейсы как базовый тип, который является внутренним для сборки, но его члены (реализации) будут общедоступны (доступны вне сборки). Если абстрактный класс не имеет какой-либо реализации, и все члены общедоступны, то следует предпочесть интерфейс. – nawfal

ответ

75

Как я понимаю, вы хотите, чтобы ваш абстрактный класс выполнялся только другими классами в одной и той же сборке (например, является внутренним), но производные классы могут быть общедоступными.

Способ сделать это, чтобы сделать абстрактный базовый класс общественности, но дать ему внутренний конструктор по умолчанию:

public abstract class MyClass 
{ 
    internal MyClass() { } 
} 

Это позволит MyClass (и, следовательно, ее членов), чтобы быть видимым и полезным для классов вне вашей сборки, но классы вне вашей сборки не могут наследовать от нее (получите ошибку компиляции).

Edit: Если классы, которые могут видно внешних сборок наследоваться от MyClass, вы не можете предотвратить MyClass от также видел - например, показывая в Intellisense. Тем не менее, вы можете предотвратить их использование , следуя приведенному выше.

+3

Мой вопрос не о промахе. Я уже это предотвратил. Речь идет о том, чтобы не загрязнять Intellisense классом, который непригоден для использования вне сборки. – m3ntat

+0

@ m3ntat см. Мой отредактированный ответ. –

+1

Вы _cannot_ делаете базовые классы менее доступными, чем производные классы. Вместо этого вы можете вместо этого использовать базовый класс (но не сам класс). – thecoop

9

Относительный базовый класс должен быть общедоступным, так как вся наследственная иерархия для класса должна быть видимой. Это гарантирует, что полиморфизм работает и действует; однако все члены базовых классов могут быть внутренними (включая конструктор) и, следовательно, непригодными для использования вне вашей сборки

+2

Что такое downvote? – thecoop

+1

Если я ошибаюсь, это не имеет ничего общего с полиморфизмом: класс может реализовать внутренний интерфейс, и превращение этого интерфейса в абстрактный класс ничего не меняет, поскольку методы наследуются и т. Д., Если на то пошло. Теоретически, можно было бы прекрасно определить класс, который имеет внутренний базовый класс, и использовать его в других сборках. Это просто, что C# (или .NET?) Этого не позволяет. –

6

На самом деле не так много пользы от того, что вы пытаетесь достичь, но то, что вы на самом деле пытаетесь достичь, похоже на это.

Имейте свой базовый базовый класс в 1 сборке со всем внутренним. В AssemblyInfo для этой сборки нужно добавить

[assembly:InternalsVisibleTo("cs_friend_assemblies_2")] 

Тогда в другой сборке у вас есть все классы, которые вы хотите общедоступными. Обратите внимание, что вы по-прежнему сможете получить доступ к базовому классу из intellisense для любого кода внутри cs_friend_assemblies_2 или того, что вы называете своей сборкой, но не где-либо еще.

+1

Я думаю, что это единственное предположение для OP, чтобы НАПРЯЖАТЬ то, что он хочет, хотя это довольно ужасный метод, но все же +1 – Letseatlunch

+1

Я, возможно, не нашел значения в том, чего хочет достичь OP, но я бы не сказал, что это ужасный подход. Это в основном открывает «сборки друзей» в .NET. Коллекции друзей, используемые в неправильных ситуациях, могут привести к ужасному коду и ужасным фреймворкам, но это будет связано с плохими практиками. Я нахожу, что наиболее нужное использование сборок друзей для тестовых проектов, а иногда и в зависимостях ServiceLayer (ex updatedBy - это {public get; internal protected set}, а службе разрешено назначать UpdateBy, но нет, где еще есть). –

+1

Я столкнулся с этим вопросом, потому что у меня была аналогичная потребность в OP и нашла ваше единственное, что действительно работало бы для OP. В моем случае, однако, это не сработает по определенным причинам, и это не вариант. Поэтому я бы не назвал это «Ужасным» решением, это преувеличение, но он чувствовал, что это больше похоже на работу с шишкой, которая не будет работать во всех случаях. – Letseatlunch

4

Вы не можете одновременно сделать класс доступным для других сборок для наследования, но также и частным, чтобы он не мог быть видимым для других потребителей. Вы можете сделать класс внутренним и выставить его на определенную сборку (если это сборка друзей), используя атрибут [InternalsVisibleTo], но я не думаю, что это то, что вы хотите.

Если вы хотите сохранить код (кроме производных классов) от того, чтобы создать экземпляр базового класса, вы могли бы дать ему защищенный конструктор:

abstract class MyBaseClass 
{ 
    protected MyBaseClass() { ... } // only inheritors can access this... 
} 

Вы можете скрывать членов класса от Intellisense, используя EditorBrowsable атрибут:

abstract class MyBaseClass 
{ 
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 
    public void SomeMethodToBeHidden() { } 
} 

следует отметить, что некоторые люди сообщали о проблемах с IDE не всегда уважая этот атрибут.

+1

EditorBrowsableAttribute действителен только для членов класса, а не для объявлений классов. –

+0

Это то, что я ищу, но это, похоже, не уважает это в Intellisense, я просто попробовал. – m3ntat

+0

Кроме того, маркировка абстрактного класса предотвращает создание экземпляра класса. Наличие защищенного конструктора по умолчанию - нет. –

0

Будут ли другие сборки когда-либо наследоваться от вашего абстрактного базового класса или любого из общедоступных классов, которые наследуют ваш абстрактный базовый класс?

Если это так, вы должны сделать открытый базовый класс общедоступным. Просто создайте методы, которые вы не хотите видеть вне сборки внутри.

Если нет, возможно, интерфейсы могут помочь? Определите общедоступные интерфейсы, сделайте ваши общедоступные классы внедряйте их и создайте фабрику для получения экземпляров. Таким образом, единственная вещь, которую intellisense видит вне сборки, - это интерфейс.

Помогло ли это?

1

Насколько я знаю, это не проблема. Обратите внимание:

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(); 
} 

выше не будет работать вообще без полиморфизма - возможность ссылаться на экземпляры различных производных классов через общий интерфейс, абстрактный базовый класс. То, что вы хотите сделать, это убрать это и испортить удобство вашей иерархии классов. Я не думаю, что вам следует продолжать этот путь.

0

Способ обойти это ограничение заключается в использовании композиции вместо наследования (есть othergood reasons, чтобы сделать это тоже). Например, вместо:

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 полностью, если общественность не нужно знать об этом, и ваши внутренности не либо.