5

I have the following code:

public abstract class NavEntityController<ChildEntity> where ChildEntity : NavObservableEntity
{
    public abstract void Delete(ChildEntity line);
    public abstract void Update(ChildEntity line);
    public abstract void Create(ChildEntity line);

    public void PushChangesToNav(NavObservableCollection<ChildEntity> lines) 
    {
        foreach (var line in lines)
        {
            line.ErrorLastAction = false;
            EntityState previousState = line.CurrentState;

            try
            {
                switch (line.CurrentState)
                {
                    case EntityState.Unchanged:
                        break;
                    case EntityState.NeedsCreate:
                        Create(line);
                        line.CurrentState = EntityState.Unchanged;
                        break;
                    case EntityState.NeedsUpdate:
                        Update(line);
                        line.CurrentState = EntityState.Unchanged;
                        break;
                    case EntityState.NeedsDelete:
                        Delete(line);
                        line.CurrentState = EntityState.Deleted;
                        break;
                }
            }
            catch (Exception e)
            {
                //...
            }        
        }
    }
}

I need a base class to inherit from this class, like such:

public class NavJobController : NavEntityController<NavObservableJob>
{
    public NavJobController( {}

    public override void Delete(NavObservableJob line) {//Implementation here}
    public override void Update(NavObservableJob line) {//Implementation here}
    public override void Create(NavObservableJob line) {//Implementation here}

    //Other functionality
}

However, I do not want someone to be able to do:

NavJobController j = new NavJobController();
j.Create(new NavObservableJob());

but only would like the following method:

j.PushToNav(); //and any other public functionality in the base class to be available

Essentially, I want to force the child class to implement CRUD operations, without exposing them to the public. The ideal syntax I was hoping for is the following:

private abstract void Delete(ChildEntity line);
private abstract void Update(ChildEntity line);
private abstract void Create(ChildEntity line);
Prabu
  • 4,097
  • 5
  • 45
  • 66
David
  • 15,652
  • 26
  • 115
  • 156

2 Answers2

13

This is why protected visibility exists (visible to both base class and derived classes, but not publicly available to use them from an instance).

If you need to publicly access these methods somewhere in your solution, you may need to use internal instead of protected and make internals visible to some assemblies using [InternalsVisibleTo] attribute.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • I've always avoided protected because of this: http://stackoverflow.com/questions/3182653/are-protected-members-fields-really-that-bad.. I've now re-read it and seen it only applies to properties – David Aug 05 '15 at 09:10
  • 1
    @David This is just an opinion. – Matías Fidemraizer Aug 05 '15 at 09:11
  • @David that answer is heavily exaggerated. There is nothing inherently wrong with protected members, or at least not more than public members. – CodeCaster Aug 05 '15 at 09:12
  • @CodeCaster Absolutely... In fact, you can provide settings by code by making some read-only properties virtual/abstract so derived classes provide the value overriding them to make everything work as expected... – Matías Fidemraizer Aug 05 '15 at 09:14
1

The way to do this is to use protected abstract. This exposes the methods to descendant types, but not to outsiders, as well as enforcing that some descendant has to implement the method.

So this is how you would declare it:

public abstract class NavEntityController<ChildEntity> where ChildEntity : NavObservableEntity
{
    protected abstract void Delete(ChildEntity line);
    protected abstract void Update(ChildEntity line);
    protected abstract void Create(ChildEntity line);

    ... rest of class
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825