Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: a way of defining a class that is only derivable within an assembly #1854

Closed
dsaf opened this issue Sep 13, 2018 · 6 comments
Closed

Comments

@dsaf
Copy link

dsaf commented Sep 13, 2018

This would allow creating sealed hierarchies which is often useful for reusable libraries with a defined scope. In some cases it's beneficial to not give the library user a false impression that a class is meant to be inheritable because it had to be made inheritable.

I am not too bothered about exhaustive type pattern matching on top of this. But if it's possible and does not require putting all classes in the same file and/or removing (polymorphic) behaviour than that's OK too. This is not about case/data/record classes, this is about normal OOP classes.

Example based on suggested public internal sealed phrase (to avoid new keywords):

//First.dll
public internal sealed class SomeComponentBase
{
    public virtual void SomeBehaviour() {}
}

public sealed class OtherComponent : SomeComponentBase
{
    public override void SomeBehaviour() {}
}
//Second.dll
#error Error CS9999 'YetAnotherComponent': cannot derive from externally sealed type 'SomeComponentBase'...
public sealed class YetAnotherComponent : SomeComponentBase
{
    public override void SomeBehaviour() {}
}

PS: introducing namespace scope in addition to assembly scope could be quite interesting too. Though this would not be limited to just this case.

@theunrepentantgeek
Copy link

Are you aware of the private protected visibility modifier?

Declaring a constructor with private protected visibility gives a class that can only be inherited within the same assembly. Make all the leaf classed sealed and you have your sealed hierarchy.

Here's an example from a series on my blog:

public abstract class ValidationResult
{
    private protected ValidationResult()
    {
    }
}

Unless, I've misunderstood the intent of your proposal?

@dsaf
Copy link
Author

dsaf commented Sep 13, 2018

I raised this proposal after having had just applied private protected and feeling that that is not enough. You made ValidationResult abstract and uninstantiable in it's own right. This is not always preferable.

@HaloFour
Copy link
Contributor

You can use internal on the constructor and provide a public static factory method to instantiate the class publicly.

There's nothing that C# can do to implement a feature like this. Without CLR support it would be exceptionally easy to avoid this limitation by using a downlevel version of the compiler, or any other language.

@jveselka
Copy link

jveselka commented Sep 13, 2018

You can also have base class with private constructor and all subclasses nested.

public abstract class Component
{
    private Component() { }
    public class Some : Component { }
    public class Other : Component { }
}

To organize it better, make base class partial and subclasses each in different file. Often the explicit scope Component.Some is better for discoverability than using suffixes or prefixes. Where it isn't, using static can help.
Edit: But I guess it is the same as what @theunrepentantgeek said just more localized

@bondsbw
Copy link

bondsbw commented Sep 14, 2018

This proposal is a duplicate of #485, where it uses the closed keyword.

One interesting feature of closed: you are not required to seal subtypes. This means that you can enforce that all derived types derive through one of the blessed subtypes you provide.

@dsaf
Copy link
Author

dsaf commented Sep 16, 2018

@bondsbw fair enough, #485 sounds close.

@dsaf dsaf closed this as completed Sep 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants