-2

I've created 3 classes, A, B and C.

  • B inherits from A
  • C inherits a Collection of A

However, I can't understand why when inheriting from a collection, the derived class can access only the protected member of the base class.

public class A
{
    public int MyPublic { get; set; }
    protected int MyProtected { get; set; }
    internal int MyInternal { get; set; }
    protected internal int MyProtectedInternal { get; set; }
}
public class B : A
{
    B MyB { get; set; }
    B()
    {
        MyB.MyProtected++;
        MyB.MyInternal++;
        MyB.MyPublic++;
        MyB.MyProtectedInternal++;
    }
}
public class C : Collection<A>
{
    C MyC { get; set; }
    C()
    {
        MyC[0].MyProtected++; // Inaccessible due to its protection level.
        MyC[0].MyInternal++;
        MyC[0].MyPublic++;
        MyC[0].MyProtectedInternal++;
    }
}
Charlie
  • 1,169
  • 2
  • 16
  • 31
Eminem
  • 143
  • 6
  • 6
    `C` does not inherit from `A`. `C` inherits from `Collection`. – BJ Myers Nov 11 '18 at 21:20
  • Is there a way to access a a protected member when I want to use this kind of architecture, when i need a subclass that **is-a** collection of a base class? – Eminem Nov 11 '18 at 21:24
  • @eminem No. Protected members are visible only within the declaring type and within derived types. You're looking for something similar to `friend` from C++, which does not exist in C#. The closest similar modifier is `internal` and then both types must be in the same assembly. However, beware of coupling your classes tightly. Make the property internal, public, or rethink your architecture. – cdhowie Nov 11 '18 at 21:25
  • [*A protected member is accessible within its class and by derived class instances.*](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected) and you are doing neither. – DavidG Nov 11 '18 at 21:25
  • You have to forget the generic type parameter. This parameter only describes the return type of a function. Sometimes the parameter type of a function. But you are not using a function of the Collection class. This is why it is not accessible – Charlie Nov 11 '18 at 21:26
  • @cdhowie So what can I do when I want a member to be accessible only in derived class, when that class **is-a** collection of it's base? – Eminem Nov 11 '18 at 21:27
  • 3
    @eminem `C` _is not_ a derived class of `A`. This sounds like an [XY problem](https://meta.stackexchange.com/a/233676/218910). Tell us what you're trying to accomplish by doing this. – cdhowie Nov 11 '18 at 21:28
  • @cdhowie I need class C to be in an **is-a** relation with class A, however it is a collection of A. Therefore I inherited a collection. In addiction I want MyProtected to be accessible only in its derived classes. – Eminem Nov 11 '18 at 21:31
  • @eminem What you ask is not possible because you're asking for two conflicting things: in C# you can only inherit _one_ class so you cannot inherit both `C` and `Collection`. You must pick one. If you state what you're trying to accomplish, perhaps there is an alternative solution. (You've only restated the Y part of XY -- what are you trying to accomplish with this pattern?) – cdhowie Nov 11 '18 at 21:32
  • @cdhowie I'm not sure what more can I add to my goal. In my real code, A represents a single paragraph, while C represents, well, a collection of paragraphs. A has a "content" member which I want to be accessible only within classes that are paragraph. Hope you can understand what I'm trying to do, sorry for the XY problem here :) – Eminem Nov 11 '18 at 21:37
  • 1
    You should not inherit from collections in the first place. – adjan Nov 11 '18 at 21:38
  • @eminem Well there you go, you said it yourself. C is a collection of paragraphs. _C is not a paragraph itself._ Therefore is not a subtype and has no business reading that protected member. – cdhowie Nov 11 '18 at 21:39
  • @cdhowie I know that C is **not-a** paragraph, that is why I inherited a collection of A, and not A alone. How would you define a collection of paragraph? Remember that C does not **has-a** collection of paragraph, but **is-a**. – Eminem Nov 11 '18 at 21:42
  • @eminem Correct, C _is-a_ collection of paragraphs, but C _is-not-a_ paragraph. This is why it cannot access the protected member. Only paragraphs can access that protected member. – cdhowie Nov 11 '18 at 21:43

2 Answers2

0

As mentioned in the comments, you aren't actually inheriting from A. You're inheriting from Collection<T>.

If your goal is to expose the protected properties of A, then make a class that inherits from A and make public properties of the same name that just modify the properties of the inherited class. Then make a collection of that new class.

Something like this. Notice the new class D:

public class D : A {
    new public int MyProtected {
        get {return base.MyProtected;}
        set { base.MyProtected = value; }
    }
    new public int MyProtectedInternal {
        get { return base.MyProtectedInternal; }
        set { base.MyProtectedInternal = value; }
    }
}
public class C : Collection<D>
{
    C MyC { get; set; }
    C()
    {
        MyC[0].MyProtected++;
        MyC[0].MyInternal++;
        MyC[0].MyPublic++;
        MyC[0].MyProtectedInternal++;
    }
}

The new modifier keyword indicates that you are replacing the property from the inherited type.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Wouldnt that expose MyProtected (for it being public now) to classes that are not derived from D? Remember I need MyProtected to be accessible only to derived classes. – Eminem Nov 11 '18 at 21:44
  • 2
    But you also seem to want it to be accessed in a `Collection`, which means it can't be `protected`. You will need to choose which is more important to you. – Gabriel Luci Nov 11 '18 at 21:47
0

Firstly, and probably not strictly relevant to your question, I'm not sure why C has a member MyC. Type C is a Collection<A> so you can just use the indexer this[int x] to access the collection items.

To give C access to ALL of the members of A while still limiting access for anything else, you could make C a nested type.

public class A
{
    protected int MyProtected { get; set; }
    private int MyPrivate { get; set; }

    public class C : Collection<A>
    {
        public void Foo()
        {
            this[0].MyProtected++; // Allowed
            this[0].MyPrivate++; // Also allowed!
        }
    }
}

Note that this gives C more access to A than you intended (all member regardless of access modifier).

Some discussion of pros/cons of nested classes here: What are reasons why one would want to use nested classes?

andrew
  • 1,723
  • 2
  • 12
  • 24