2

I have the following situation and I want to know how I can make the property SomeNumber to be read only from instances of class A? BTW, I am using C# latest stable build, or not 7.2 c#, so I can't use private protected modifier.

So I don't want to be able to set SomeNumber on accident from class A. I know it can be written in another way to achieve it but can I make the setter in class A's property only visible to class B's property setter? So you can still read SomeNumber from instances of A. Thanks.

I want to to this because I have multiple classes, not only B, derived from class A that hides the base property and they all need to run their own methods when setting SomeNumber.

class A
{
    private int someNumber;
    internal int SomeNumber
    {
        get { return someNumber; }
        set
        {
            someNumber = value;
            SomethingNotSpecificForDerivedClasses();//I prefer not to move this to each derived setter! There are more derived classes than just B, fyi
        }//I NEED TO MODIFY THE ACCESS OF THIS
    }

    private void SomethingNotSpecificForDerivedClasses()
    {
        ...
    }
}
class B : A
{
    new internal int SomeNumber//hides base member
    {
        get { return base.SomeNumber; }
        set
        {
            base.SomeNumber = value;//ONLY THIS SETTER SHOULD BE ALLOWED TO DO THIS
            SomethingINeedToRunWhenSettingSomeNumber();
        }
    }

    private void SomethingINeedToRunWhenSettingSomeNumber()
    {
        ...
    }
}
Cheyenne
  • 25
  • 7
  • 1
    Just so i understand you want to be able to get SomeNumber in class A but only set it in B and other inherited classes? – Robert Juneau Dec 07 '17 at 19:57
  • @RobertJuneau - that is how I understand it, yes. The OP indicates that A will actually be inherited by multiple classes (B, C, D, E, etc) which will each have specific code to run when the property is set. – Jeff Dec 07 '17 at 20:05
  • @Robert, correct, get only for ((A)new B()).SomeNumber but set and get for new B().SomeNumber! I updated the code because I forgot a detail. There is non specific code for the derived classes called in the base setter as well. Basically I dont want to move it to each derived class by eliminating the base setter. – Cheyenne Dec 07 '17 at 20:12
  • Are you ever going to create an instance of class A? – Robert Juneau Dec 07 '17 at 20:18
  • No but I may I have references to it. I will never create anywhere but derived constructor. – Cheyenne Dec 07 '17 at 20:21
  • If you are not going to create an instance of class A it makes sense to make class abstract to prevent creating instances class abstract A – Daniil Grankin Dec 07 '17 at 21:11

2 Answers2

1

If you want to run a particular method in the setter perhaps you can simply declare a virtual method?

public class A
{
    private int _someNumber;

    internal int SomeNumber
    {
        get { return _someNumber; }
        set
        {
            _someNumber = value;
            SomethingINeedToRunWhenSettingSomeNumber();
        }
    }

    protected virtual void SomethingINeedToRunWhenSettingSomeNumber()
    {
        // Do something generic to A.
    }
}

public class B : A
{
    protected override void SomethingINeedToRunWhenSettingSomeNumber()
    {
        base.SomethingINeedToRunWhenSettingSomeNumber();

        // Do something specific to B.
    }
}
Daniil Grankin
  • 3,841
  • 2
  • 29
  • 39
Derrick Moeller
  • 4,808
  • 2
  • 22
  • 48
  • 1
    I don't think abstract is suitable. It should be just virtual with some implementation. See my answer. – Daniil Grankin Dec 07 '17 at 20:22
  • Hi Derrick, thanks for the reply, can you check the edited post. I forgot that I am running code not specific to the derived classes in the base setter. I would prefer to prevent instance of A being able to have this property set. To set I would want to have to cast to a derived class. I will have references of A to deal with. – Cheyenne Dec 07 '17 at 20:25
  • I was thinking I may go this route and just allow the setter in instances of A to be called and let it run the correct override based on derived type. Thanks. – Cheyenne Dec 07 '17 at 20:28
  • @Cheyenne In that case you can make the base method virtual and simply call it from the implementation in `B`. – Derrick Moeller Dec 07 '17 at 20:29
0

Just like with any other override method, you need to make your base class method virtual, and use the 'override' keyword on your subclass.

Within the class, you can then call the base class' method to set the value, so it will run the base-class setter.

Your end result could look like this:

Class A
{
    private int someNumber;
    internal virtual int SomeNumber
    {
        get { return someNumber; }
        set { someNumber = value; }
    }
}
Class B : A
{
    internal override int SomeNumber
    {
        get { return base.SomeNumber; }
        set
        {
            base.someNumber = value;
            SomethingINeedToRunWhenSettingSomeNumber();
        }
    }

    private void SomethingINeedToRunWhenSettingSomeNumber()
    {
        ...
    }
}
Jeff
  • 2,835
  • 3
  • 41
  • 69
  • I see, but if I were to set the value of 'SomeNumber' on an instance of A, which calls the abstract method, would it determine the type and then call the correct override? – Cheyenne Dec 07 '17 at 20:00
  • @Cheyenne Yes. When you interact with a subclass, it runs the overrides from that subclass. – Jeff Dec 07 '17 at 20:01
  • Oh ok, I misuderstood, thanks. That is right. I forgot to add one detail for my situation. I will edit my code above. The problem is, the base setter also runs code which is not specific to the derived classes. So I dont want to move that code to each class. Your answer would work in the example though. +1 Please see my edit momentarily and thanks again. – Cheyenne Dec 07 '17 at 20:08
  • @Cheyenne - I have updated this answer taking the new detail into account. In this case, when both base and derived class have code that needs to run, override is the way to go (as opposed to the hiding that 'new' causes). Derrick's suggestion of an abstract method which is always called by the base setter, however, would work as well. – Jeff Dec 07 '17 at 20:16
  • @Cheyenne - just a friendly reminder about the use of this site: if an answer solves your problem, you can 'Approve' it by clicking the check mark. If an answer was helpful (or not!) you can vote it up or down as appropriate by clicking the 'up' or 'down' arrows. Downvoting, however, may require more rep than you have. – Jeff Dec 07 '17 at 20:24
  • Hi Jeff. I think I may go with the abstract method in the base because I need a base specific method called in the base setter so I dont want to prevent that from being called. If I override would I need to move that method to each derived class so the override could call it? – Cheyenne Dec 07 '17 at 20:37
  • @Cheyenne - You would. The suggestion to use an overridden method in each base class, and call that method from the base class (which does NOT have to be abstract, but it can be) is an elegant fix. – Jeff Dec 07 '17 at 20:43
  • 1
    @Cheyenne you can use `abstract` but in that case you will not be able to use coomon stuff so use `virtual` and `override` as you need and it will be called as you want so you don't need to put this common stuff in each derived class – Daniil Grankin Dec 07 '17 at 20:45
  • I see. Thanks for all the info! – Cheyenne Dec 07 '17 at 20:50