Reputation: 153
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!
Upvotes: 0
Views: 181
Reputation: 153
@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.
Upvotes: 0
Reputation: 73482
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.
Upvotes: 1