Hiding/restricting generic base class direct usage from other assemblies [duplicate] - c#

I have a common assembly/project that has an abstract base class, then several derived classes that I want to make public to other assemblies.
I don't want the abstract base class to show up in these other assemblies in Intellisense, so I thought I'd make it internal, but I get this error:
Inconsistent accessibility: base class 'Settings' is less accessible than class 'IrcSettings' ....
I don't really get this. I am forced to make the abstract Settings class public, and thus visible outside this assembly.
How can I make this class internal instead?

As I understand, you want your abstract class to only be implemented by other classes in the same assembly (e.g. it is internal) but the derived classes could be public.
The way to do this is to make the abstract base class public, but give it an internal default constructor:
public abstract class MyClass
{
internal MyClass() { }
}
This will allow MyClass (and hence its members) to be visible and usable to classes outside your assembly, but classes outside your assembly cannot inherit from it (will get a compile error).
Edit: If classes which can be seen by external assemblies inherit from MyClass, you cannot prevent MyClass from also being seen - e.g., showing up in Intellisense. However, you can prevent them from being used by following the above.

The abstract base class has to be public, as the entire inheritance heirarchy for a class has to be visible. This ensures the polymorphism works and is valid; however all the base classes' members can be internal (including the constructor), and hence not usable outside your assembly

There really isn't much of a benefit to what you're trying to achieve but what you're actually looking to achieve is similar to this.
Have your abstract base class in 1 assembly with everything internal. In the AssemblyInfo for that assembly you need to add
[assembly:InternalsVisibleTo("cs_friend_assemblies_2")]
Then in another assembly you have all the classes you want publicly available. Note you will still be able to access the base class from intellisense for any code inside cs_friend_assemblies_2 or whatever you name your assembly but not any where else.

You can't simultaneously make the class available to other assemblies for inheritance but also private so it can't be visible to other consumers. You can make the class internal, and expose it to a specific assembly (if it's a friend assembly) using the [InternalsVisibleTo] attribute, but I don't think this is what you want.
If you want to keep code (other than derived classes) from being able to instantiate your base class, you could give it a protected constructor:
abstract class MyBaseClass
{
protected MyBaseClass() { ... } // only inheritors can access this...
}
You can hide the class members from Intellisense using the EditorBrowsable attribute:
abstract class MyBaseClass
{
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void SomeMethodToBeHidden() { }
}
It should be noted that some people have reported problems with the IDE not always respecting this attribute.

As far as I'm concerned, this is a non-problem. Observe:
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();
}
The above wouldn't work at all without polymorphism -- being able to refer to instances of different derived classes through their common interface, the abstract base class. What you want to do is take that away and cripple the usability of your class hierarchy. I don't think you should continue down this path.

Will the other assemblies ever inherit from your abstract base class or any of the public classes that do inherit from your abstract base class?
If so, you have to make the abstract base class public. Just make methods you don't want visible outside the assembly internal.
If not, maybe interfaces can help? Define public interfaces, make your public classes implement them, and provide a factory to get instances. That way the only thing intellisense sees outside the assembly is the interface.
Does that help?

A way to work around this limitation is to use composition instead of inheritance (there are other good reasons to do this too). For example, instead of:
internal abstract class MyBase
{
public virtual void F() {}
public void G() {}
}
public class MyClass : MyBase // error; inconsistent accessibility
{
public override void F() { base.F(); /* ... */ }
}
Do this:
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(); }
}
You can omit the IMyBase interface entirely if the public doesn't need to know about it and your internals don't either.

Related

How to prevent a class from being inherited outside the library, while being inherited by public classes?

Suppose I have the following classes in a library
public abstract class HiddenBaseClass
{
//stuff
}
public abstract class ClassA : HiddenBaseClass
{
//stuff
}
public abstract class ClassB : HiddenBaseClass
{
//stuff
}
I want to prevent HiddenBaseClass from being inherited outside the library, but I do want ClassA and ClassB to be inherited.
I cannot make HiddenBaseClass an internal class, because that would mean HiddenBaseClass is less accessible than ClassA and ClassB.
Is there a way around this?
Contrary to the comments on the question, I believe this scenario can make sense, if HiddenBaseClass has aspects that you need to rely on being implemented internally (because you trust the internal implementations), but expose other abstract operations for external code to implement. It may not be an appropriate design for your use case, but it's not unreasonable.
One simple way to make it impossible to inherit from it directly outside the same library is to give it an internal constructor:
public abstract class HiddenBaseClass
{
// Only classes in the same assembly can chain to this constructor.
internal HiddenBaseClass() {}
}
So long as all the constructors in the class are internal (or private protected, or private) that will prevent classes in other assemblies from chaining their constructors to the base class constructors, thus preventing inheritance.
As the comments so politely pointed out, this isn't the best structure for this kind of scenario. In the end I'm going for an implementation like this:
internal sealed class HiddenBaseClass
{
//stuff
}
public abstract class ClassA
{
internal HiddenBaseClass { get; set; }
//stuff that uses HiddenBaseClass
}
public abstract class ClassB
{
internal HiddenBaseClass { get; set; }
//more stuff
}
I apologise for asking the wrong questions yet again.

How not to allow exposing classes derived from a specific class?

Assume that a component (say CompA) exposes a public C# .NET class (say Base) in an SDK:
namespace CompA { public abstract class Base {} }
A different component (say ExtB) extends CompA by deriving from this base class:
namespace ExtB { class Derived : CompA.Base {} }
What is your opinion, what is the best approach to not to allow declaring class ExtB.Derived as public, please? CompA.Base is meant for extending CompA, but not for exposing new public API with it.
namespace ExtB { public class Derived : CompA.Base {} } // DISALLOW
What I can think for is to expect assemblies exposing public API to be marked with a .NET custom attribute and mark the base class with another .NET custom attribute. The product that loads these assemblies would then not allow such assembly to load that exposes/publishes such types that derive from types marked with the custom attribute.
AssemblyInfo.cs of CompA:
[assembly:SdkApiAssemblyAttribute()]
AssemblyInfo.cs of ExtB:
[assembly:SdkApiAssemblyAttribute()]
Base.cs:
namespace CompA
{
[Publishable(false)]
public abstract class Base {}
}
Thanks!
At first it sound you're doing something wrong. After confirming that your intention is just to prevent exposing the type accidentally, It sounds reasonable. It might be simple to write a unit test, but if Derived classes are not part of your code base you can do the following.
There is no compile time way to prevent this(AFAIK). Just check the type in Base class constructor and throw exception.
public abstract class Base
{
protected Base()
{
if (this.GetType().IsPublic)
throw new InvalidOperationException("Type is not meant to be exposed public");
}
}
public class Der : Base
{
public Der()
{
}
}
This will prevent the client from creating new instance of Der if it is declared as public.
Note: There are some scenarios that constructor will not run, You're out of luck then. Fortunately they are corner cases, not to be worried about much. For Example: FormatterServices.GetUninitializedObject won't run the constructor.
#SriramSakthivel, you are correct: I did something wrong! :)
Although not intentionally I did not say that CompA.Base was actually not a class, but an interface!
public interface Base
{
string ShouldNotBePublic();
}
The base class should expose the method with protected access modifier:
public abstract class Base
{
protected string ShouldNotBePublic();
}
This way the derived class will not acidentally expose the protected information. The component CompA is then able to access this method by implementing the template method patter:
namespace CompA
{
public abstract class Base : IBaseInternal
{
protected string ShouldNotBePublic();
string IBaseInternal.ShouldNotBePublic()
{
return ShouldNotBePublic();
}
}
internal interface IBaseInternal
{
string ShouldNotBePublic();
}
}
Sorry for the confusion.

Why I must declare field as "public" in abstract class to access it from derived classes?

I have CPU and human player so I decided to use abstract class in order to define common features. While their methods will differ, the field piecesToPlace will be the same for both.
I do not understand why it must be public, I thought that is like regular inheritance. I do not want this list to be public but it does not work otherwise.
abstract class Player
{
abstract public void Move(Piece p);
abstract public void Place(Piece p);
abstract public void TakeP(Piece p);
List<Piece> piecesToPlace = new List<Piece>();
}
It doesn't have to be public, but it does have to be internal, assuming the inherited class is in the same namespace, protected, or internal protected. An abstract class can define behavior as well as an interface. So, it still may want to hide implementation details.
The default for class members is private, so unless you specify any other access modifier for the piecesToPlace, it will only be accessible inside the Player class.
You don't have to make it public, using protected would make it accessible to inheriting classes.
It sounds like you are after the protected keyword, this will:
Access is limited to the containing class or types derived from the
containing class.
Have a look here for more information: http://msdn.microsoft.com/en-us/library/ba0a1yw2(v=vs.110).aspx
The logic is simple , it depends on how you need it. If you define it public , for eg:
class Base
{
abstract public void Print();
}
class Derived: Base
{
public override void Print()
{}
}
Main()
{
Base base = new Derived();
//its possible
base.Print();
}
if you define it as protected then base.Print is not possible to access(intellisense will not even show that such method exists). Since these methods can be only accessible from the derived class.

How do I create a method or property in C# that is public, yet not inheritable?

Here is an example. I have two classes, one inherited, and both have a function with the same name, but different arguments:
public class MyClass
{
//public class members
public MyClass()
{
//constructor code
}
public void Copy(MyClass classToCopy)
{
//copy code
}
}
public class InheritedClass : MyClass
{
//public class members
public InheritedClass():base()
{
//constructor code
}
public void Copy(InheritedClass inheritedClassToCopy)
{
//copy code
}
}
My question is how do I make the base class' copy method (MyClass.Copy) non-inheritable or non-visible in InheritedClass? I don't want to be able to do this:
MyClass a;
InheritedClass b;
b.Copy(a);
Does this make sense, or should I keep this functionality in there? Can what I'm asking even be done?
Does this make sense, or should I keep this functionality in there? Can what I'm asking even be done?
Trying to hide a public method like this when used by a base class is problematic. You're purposely trying to violate the Liskov substitution principle.
You can't do what you are wanting to do here; C# does not allow negative variance in inherited members. (almost no languages truly do, actually)
It may be that you don't want an inherited class here at all, though; what you may really want is an interface. Or... your two classes here may not have the correct relationship; perhaps they should both instead be common siblings of a third class, which is their parent.
You can use explicit interface implementation to hide this method from the inheritor. But you will need to add an interface of course and you will need to cast your type to the interface to call your method:
public interface MyInterface
{
void Copy(MyClass classToCopy)
}
public class MyClass : MyInterface
{
void MyInterface.Copy(MyClass classToCopy)
{
//copy code
}
}
This is not possible. An inherited class inherits all public and protected members, methods and properties. Using the sealed modifier with make it non-overridable, but still accessible to your inherited class.
What everyone else said, but if I am inferring your goal correctly, it is to make sure that InheritedClass users never use the MyClass method. In that case, exclude it from MyClass and make two classes that inherit it.
Make MyBaseClass abstract if it should not be instantiated (most likely).
(Edited -- you probably would want to include copy code for anything that's part of the base class in the base class)
public abstract class MyBaseClass
{
public MyClass()
{
//constructor code
}
protected void Copy(MyBaseClass classToCopy)
{
//copy code
}
// other methods that all inherited classes can use
}
public class MyClass: MyBaseClass
{
public MyClass():base()
{
//constructor code
}
public void Copy(MyClass myClassToCopy)
{
base.Copy(myClassToCopy);
//specific copy code for this extensions in this class
}
}
public class InheritedClass : MyBaseClass
{
public InheritedClass():base()
{
//constructor code
}
public void Copy(InheritedClass inheritedClassToCopy)
{
base.Copy(myClassToCopy);
//specific copy code for this extensions in this class
}
}

Abstract class does not implement interface

I have an interface so class writers are forced to implement certain methods. I also want to allow some default implemented methods, so I create a abstract class. The problem is that all classes inherit from the base class so I have some helper functions in there.
I tried to write : IClass in with the abstract base, but I got an error that the base didn't implement the interface. Well of course because I want this abstract and to have the users implement those methods. As a return object if I use base I can't call the interface class methods. If I use the interface I can't access base methods.
How do I make it so I can have these helper classes and force users to implement certain methods?
Make sure methods in the base class have the same name as the interface, and they are public. Also, make them virtual so that subclasses can override them without hiding them.
interface IInterface {
void Do();
void Go();
}
abstract class ClassBase : IInterface {
public virtual void Do() {
// Default behaviour
}
public abstract void Go(); // No default behaviour
}
class ConcreteClass : ClassBase {
public override void Do() {
// Specialised behaviour
}
public override void Go() {
// ...
}
}
Move the interface methods into the abstract class and declare them abstract as well. By this, deriving classes are forced to implement them. If you want default behaviour, use abstract classes, if you want to only have the signature fixed, use an interface. Both concepts don't mix.
Having faced with the same problem recently, I've came up with a somewhat more elegant (to my mind) solution. It looks like:
public interface IInterface
{
void CommonMethod();
void SpecificMethod();
}
public abstract class CommonImpl
{
public void CommonMethod() // note: it isn't even virtual here!
{
Console.WriteLine("CommonImpl.CommonMethod()");
}
}
public class Concrete : CommonImpl, IInterface
{
void SpecificMethod()
{
Console.WriteLine("Concrete.SpecificMethod()");
}
}
Now, according to C# spec (13.4.4. Interface mapping), in the process of mapping IInterface on Concrete class, compiler will look up for CommonMethod in CommonImpl too, and it doesn't even have to be virtual in the base class!
The other significant advantage, compared to Mau's solution, is that you don't have to list every interface member in the abstract base class.

Categories

Resources