0

If I have 3 classes as follows:

abstract class A {}

public class B : A {}

public class C: A {}

I want to force other code to use B or C directly, or inherit from either B or C. I don't want other code to inherit directly from A.

Is this even possible?

A cannot be private since B and C must be public, making A private would cause "Inconsistent accessibility". A can't be internal for the same reason.

Why do I want this?

I have designed an API, the response of which must include either property x, or both properties y & z, but not all 3. It also includes a bunch of other properties that are common to both possibilities. i.e. -

{
  "allOf": [
    {
      "type": "object",
      "properties": {
        "w": { ... }
      }
    }, 
    {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "x": { ... }
          }
        }, 
        {
          "type": "object",
          "properties": {
            "y": { ... },
            "z": { ... }
          }
        }
      ]
    }
  ]
}
DJL
  • 2,060
  • 3
  • 20
  • 39
  • While writing out the question, I've actually realised that I don't need this after all, since it would actually be useful to still have property x (but auto-generated) on the y+z output, thus I can simplify the class structure. Keeping the question active though since it could be useful to others. – DJL Sep 14 '20 at 10:41
  • 8
    Make the constructor(s) of `A` `internal`? – Damien_The_Unbeliever Sep 14 '20 at 10:41
  • 1
    Does this answer your question? [Can I make a type "sealed except for internal types"](https://stackoverflow.com/questions/3072119/can-i-make-a-type-sealed-except-for-internal-types) – Mathias R. Jessen Sep 14 '20 at 10:44
  • Kind of, except `internal` won't really work for me since the "other" code I mentioned is actually in the same library. It might work if this wasn't the case though. If it helps, A, B + C are all in the same file. (B + C are stubs) – DJL Sep 14 '20 at 10:47
  • how about using interfaces? – SaschaP Sep 14 '20 at 11:00

1 Answers1

3

If you make B and C part of A you can mark the constructor of A private so no other classes can inherit directly from A:

public class A
{
    private A()
    {

    }

    public class B: A
    {
        public B()
        {

        }
    }

    public class C: A
    {
        public C()
        {

        }
    }
}

The downside however is that you now have to refer to B as A.B (see edit, this is not needed), but functionality wise the rest of the application is able to instantiate and use classes of type A.B and A.C and inherit from them while prohibiting the ability to instantiate or use A directly (even in the same file/assembly).

So this is invalid anywhere outside of A:

public class D: A
{

}

But this you can use anywhere:

public class E : A.B
{

}

Edit: As noted by Jonathan Barclay you prevent having to use A.B by the following using directive, which will allow you to inherit as normal:

using static MyNamespace.A;

public class D : B
{

}
  • Now that I've seen this, its pretty obvious! I guess also there is nothing to stop from doing this outside of A, but still in the same file: `public class B : A.B { }` – DJL Sep 14 '20 at 12:18
  • 1
    "_The downside however is that you now have to refer to `B` as `A.B`_" Not necessarily; you can add `using static YourNamespace.A;`. – Johnathan Barclay Sep 14 '20 at 12:20