3

I have the following classes:

public class Essentials 
{
    public void DoSomething() 
    {
         //doing base stuff...
    }
}

public class NetworkEssentials : Essentials 
{
    public void DoNetworkSomething()
    {
        //doing something
    }
}

public class someClass : NetworkEssentials
{
    public void DoSomeSomething()
    {
        base.DoSomething(); //The thing I would like to prevent, as to block this from happening.
//attention: i dont want to change methods names so it will call the first parent, i still want to maintain a different method names to each class type
    }
}

I want to prevent someClass from being able to invoke methods in its parent's parent, only allowing direct inherit classes to invoke its base methods.

Is there anyway to do it?

Additional explanation:

basically, i have some mandatory fields i require that each object have, but there are some objects, not all, i demand to have an extra mandatory field. lets call them 1 2 3 , whereas 1 is the top parent. i want class 3 to call a class 2 method and this class 2 method will call the class 1 method, because only class 2 have this "extra" field. class 1 cant handle with this field because it doesnt recognize it at all

Ori Refael
  • 2,888
  • 3
  • 37
  • 68
  • See http://stackoverflow.com/questions/33115 for a discussion of private inheritance. In short: Consider having NetworkEssentials contain an Essentials, rather than being an Essentials. – Moby Disk Sep 17 '15 at 16:42
  • Why do you want to do it at the first place? There's no language construct that would enable such behavior. – Ondrej Tucny Sep 17 '15 at 16:43
  • If NetworkEssentials is in the same module as Essentials, "internal" might work for you. – Moby Disk Sep 17 '15 at 16:43
  • @OndrejTucny basically, i have some mandatory fields i require that each object have, but there are some objects, not all, i demand to have an extra mandatory field. lets call them 1 2 3 , whereas 1 is the top parent. i want class 3 to call a class 2 method and this class 2 method will call the class 1 method, because only class 2 have this "extra" field. class 1 cant handle with this field because it doesnt recognize it at all. – Ori Refael Sep 17 '15 at 16:46
  • @OriRefael that sounds pretty standard, not sure why this special hiding would be required for it, unless for some reason 3 directly calling 1 would break something. – BradleyDotNET Sep 17 '15 at 16:47
  • @OriRefael Does NetworkEssentials need to be able to access `DoSomething`? If not, you could mark `DoSomething()` as private in the base class. – Jordan Parmer Sep 17 '15 at 16:50
  • Note that with `public` methods you can always cast `this` to base class and call that... Possibly using `virtual` may help. – Alexei Levenkov Sep 17 '15 at 16:50
  • @BradleyDotNET exactly whats happening, it would break a thing. cause class 2 should create an instance of a field. when calling from 3 to 1, this field gonna be null – Ori Refael Sep 17 '15 at 16:50
  • @OriRefael But 1 doesn't care about that field, so it shouldn't matter. Your design seems highly fragile here. – BradleyDotNET Sep 17 '15 at 16:51
  • It sounds like you're trying to violate the basic fact that inheritance is an `is-a` relationship. Every instance of `someClass` is also an instance of `Essentials` according to your declarations. – Brian Rasmussen Sep 17 '15 at 17:00

5 Answers5

5

You could use internal and have NetworkEssentials in the same assembly. (While .NET does have an access type for the intersection of internal and protected, which would be perfect here, C# does not, so you'll have to make do with internal [Update: As of C# 7.2 there is now private protected to use that intersection]).

You could have:

public class NetworkEssentials : Essentials 
{
  new protected void DoSomething() 
  {
    throw new InvalidOperationException();
  }
}

So the DoSomething is hidden as far as the child goes. (It can't be public in Essentials or else someClass can see it the same as any other code).

It is still possible to get to DoSomething with some convoluted approaches though, and it doesn't provide a compile-time block.

basically, i have some mandatory fields i require that each object have, but there are some objects, not all, i demand to have an extra mandatory field. lets call them 1 2 3 , whereas 1 is the top parent. i want class 3 to call a class 2 method and this class 2 method will call the class 1 method, because only class 2 have this "extra" field. class 1 cant handle with this field because it doesnt recognize it at all

Well, solve that problem then. If NetworkEssentials knows how to call DoSomething() correctly, just override DoSomething() appropriately:

public class Essentials
{
  public virtual void DoSomething()
  {
    //Do stuff with field 1
  }
}

public class NetworkEssentials : Essentials
{
  public override void DoSomething()
  {
    base.DoSomething(); // handle field 1
    // Code to handle other fields either here, before the call to base.DoSomething(), or both.
  }
}

Don't attempt to block calls to DoSomething(), but use virtual methods to ensure they do the right thing. This is necessary anyway because non-inheriting code calling DoSomething() still needs the correct behaviour.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • checked, DoSomething is still visible to class 3 type. i think because its still public and inherited from class 2 – Ori Refael Sep 17 '15 at 17:00
  • And what happens when you call it? – Jon Hanna Sep 17 '15 at 17:01
  • @Jon_Hanna problem is, i want to hide it. you see my problem? its like making a field public but when u access it ill throw an exception because ill simulate private. i dont want this option to appear at all. if you think this is impossible, ill accept this answer and live with it :( – Ori Refael Sep 17 '15 at 17:04
  • To be hidden entirely, my first sentence shows the only approach (and it's indeed done a lot); use `internal`. From your later edit though, I don't see why you want to hide rather than make it virtual. – Jon Hanna Sep 17 '15 at 18:35
  • In C# 7.2 we can now use `private protected` as to mean internal and protected. – 5argon May 09 '18 at 17:35
  • @5argon indeed, it was me who made `dynamic` respect that access level in .NET Core. I'll edit to update. – Jon Hanna May 10 '18 at 10:15
1

I think you are looking for virtual - if you override method in derived class than children of that derived class will only be able to call derived's implementation (and there is absolutely no way to call top level one):

public class Essentials 
{
    virtual public void DoSomething() 
    {
         //doing base stuff...
    }
}

public class NetworkEssentials : Essentials 
{
    override public void DoSomething() 
    {
       base.DoSomething();
       // and other struff
    }

    public void DoNetworkSomething()
    {
        //doing something
    }
}

public class someClass : NetworkEssentials
{
    public void DoSomeSomething()
    {
        // can ONLY call nearest parent's that implements DoSomething 
        // so next calls NetworkEssentials.DoSomething 
        base.DoSomething(); 
    }
}
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • I agree that i can use the same method name for the entire chain and this will work as i desire. you are right with your answer, but i DO want to make distinctive naming according to the class 'type' i described. – Ori Refael Sep 17 '15 at 17:03
1

You can add a new implementation for whatever method from the base that you want to override. In this case you can have a new implementation for Dosomething in networkessentials and any derived class call to that method will only go through the NetworkEssentials. It wont stop you from calling the method but you can stop it from making the call directly to the base class which in essence is what you are trying to do I guess

public class Essentials
{
    public void DoSomething() 
    {
         //doing base stuff...
    }
}

public class NetworkEssentials : Essentials
{
    public void DoNetworkSomething()
    {
        //doing something
    }

    protected new void DoSomething() 
    {
         
    }
}

public class someClass : NetworkEssentials
{
    public void DoSomeSomething()
    {
        base.DoSomething(); //This will go thru NetworkEssentials and not directly to Dosomething
    }
}
XtremeBytes
  • 1,469
  • 8
  • 12
  • agree, it is going to work. but as i told to Alexi in one of the suggested answers, i DO want to make distinctive method names according to the class 'type' – Ori Refael Sep 17 '15 at 17:06
  • You can create additional methods with meaningful names if you want and make this new method call those. All these are just workarounds. But if you really want to hide something from a base, I would see that as a design flaw and revisit you class to define them appropriately to start with. – XtremeBytes Sep 17 '15 at 17:11
  • I see, so you're telling me its wrong. in this case, ill accept the first answer who solved it. thanks. – Ori Refael Sep 17 '15 at 17:12
1

I'm not sure what the issue is. Can't you solve this with plain old virtual and overriden methods?

public class Essentials 
{
    public virtual void DoSomething() 
    {
         //do what needs to be done at this level
    }
}

public class NetworkEssentials : Essentials 
{
    public override void DoSomething()
    {
        //do what needs to be done at this level
        base.DoSomething(); //launch what needs to be done at Essentials' level.
    }
}

public class someClass : NetworkEssentials
{
    public override DoSomething()
    {
        //do what needs to be done at this level
        base.DoSomething(); //launch what needs to be done at NetworkEssentials' level.
    }
}

Note that this way, the derived class can only call it's parent's implementation. There is no way you could skip a level in the hierarchy and get SomeClass to directly call Essentials.DoSomething bypassing NetworkEssentials.DoSomething.

This example will chain the execution of your DoSomething logic from top to bottom (from most derived to least derived). It is just as easy to chain the execution from bottom to top, simply call the base implementation before instead of after the logic specific to each class.

UPDATE

You could arguably abuse a little the type system to get the behaviour you want with the following pattern:

public class Essentials
{
    private void DoSomething()
    {
        //doing base stuff...
    }

    public class NetworkEssentials : Essentials
    {
        public void DoNetworkSomething()
        {
            //doing something
            base.DoSomething(); //Perfectly OK
        }
    }
}

public class SomeClass : Essentials.NetworkEssentials
{
    public void DoSomeSomething()
    {
       base.DoSomething(); //Compile time error
    }
}

This really whole setup looks wierd but I have very little information to asses if this is really justified.

InBetween
  • 32,319
  • 3
  • 50
  • 90
0

No, with that inheritance structure you can't do that. As @MobyDisk noted, you may consider using composition instead of inheritance to accomplish this task.

You can mark methods as protected to restrict access to only derived classes, but there is no way to force derived classes of derived classes to not have access.

Makes sense, really. If you have an Animal with an Eat method, Dog would have access to that, and so should Beagle (which would derive from Dog).

Even using method hiding doesn't work.

public class Essentials
{
    protected void DoSomething()
    {
        //doing base stuff...
    }
}

public class NetworkEssentials : Essentials
{
    public void DoNetworkSomething()
    {
        //doing something
    }

    private new void DoSomething()
    {

    }
}

public class someClass : NetworkEssentials
{
    public void DoSomeSomething()
    {
        base.DoSomething(); //The thing I would like to prevent
    }
}

Compiles just fine.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • problem is not compiling, its the think i would like to prevent doing. i dont want this child-of-child class to be able to call the parent's parent method. – Ori Refael Sep 17 '15 at 16:49
  • @OriRefael "Prevent" here means "won't compile". There is no other way to prevent the call from happening – BradleyDotNET Sep 17 '15 at 16:51
  • @BradletDotNET perhaps i was misleading, i meant to not allowing this child from doing stuff, re-edited my question. – Ori Refael Sep 17 '15 at 16:53
  • @OriRefael So what *do* you expect/want to happen if the child tries to write `base.DoSomething`? – BradleyDotNET Sep 17 '15 at 16:54