views:

356

answers:

4

I have this situation that when AbstractMethod method is invoked from ImplementClass I want to enforce that MustBeCalled method in the AbstractClass is invoked. I’ve never come across this situation before. Thank you!

public abstract class AbstractClass
{
    public abstract void AbstractMethod();

    public void MustBeCalled()
    {
        //this must be called when AbstractMethod is invoked
    }
}

public class ImplementClass : AbstractClass
{
    public override void AbstractMethod()
    {
        //when called, base.MustBeCalled() must be called.
        //how can i enforce this?
    }
}
A: 

Why can't you just call the method in the AbstractMethod() of Implement class?

Jagannath
+4  A: 

How about

public abstract class AbstractClass
{
    public void AbstractMethod()
    {
        MustBeCalled();
        InternalAbstractMethod();
    }

    protected abstract void InternalAbstractMethod();

    public void MustBeCalled()
    {
        //this must be called when AbstractMethod is invoked
    }
}

public class ImplementClass : AbstractClass
{
    protected override void InternalAbstractMethod()
    {
        //when called, base.MustBeCalled() must be called.
        //how can i enforce this?
    }
}
Simon Wilson
In this implementation, I don't think you've forced the user to call MustBeCalled. When AbstractClass.AbstractMethod is called, ImplementClass.AbstractMethod is called, but MustBeCalled isn't. I believe yshuditelu has the better solution
MedicineMan
+5  A: 

An option would be to have the Abstract class do the calling in this manner. Otherwise, there is no way in c# to require an inherited class to implement a method in a certain way.

public abstract class AbstractClass
{
    public void PerformThisFunction()
    {
        MustBeCalled();
        AbstractMethod();
    }

    public void MustBeCalled()
    {
        //this must be called when AbstractMethod is invoked
    }

    //could also be public if desired
    protected abstract void AbstractMethod();
}

public class ImplementClass : AbstractClass
{
    protected override void AbstractMethod()
    {
        //when called, base.MustBeCalled() must be called.
        //how can i enforce this?
    }
}

Doing this creates the desired public facing method in the abstract class, giving the abstract class over how and in what order things are called, while still allowing the concrete class to provide needed functionality.

Timothy Carter
*** Thank you. ***
Jeffrey C
I have used this pattern as well. I believe this is actually one of the Gang Of Four design patterns, but I don't have my book here to confirm that.
MedicineMan
How about raising event when Base.AbstractMethod() is called?
Jeffrey C
I think it's called 'Template Pattern'. Also, I think Simon's solution is a better approach. In the above code, calling code may call AbstractMethod directly without going through PerformFunction method.
SolutionYogi
A: 

One thing the preceding solutions ignore is that ImplementClass can redefine MethodToBeCalled and not call MustBeCalled -

public abstract class AbstractClass
{
    public abstract void AbstractMethod();

    private void MustBeCalled()
    {
        //will be invoked by  MethodToBeCalled();
        Console.WriteLine("AbstractClass.MustBeCalled");
    }

    public void MethodToBeCalled()
    {
        MustBeCalled();
        AbstractMethod();
    }
}

public class ImplementClass : AbstractClass
{
    public override void AbstractMethod()
    {
        Console.WriteLine("ImplementClass.InternalAbstractMethod");
    }

    public new void MethodToBeCalled() {
        AbstractMethod();
    }
}

If only C# allowed non-overridden methods to be sealed - like Java's final keyword!

The only way I can think of to overcome this is to use delegation rather than inheritance, because classes can be defined as sealed. And I'm using a namespace and the "internal" access modifier to prevent providing a new implementation on implementing classes. Also, the method to override must be defined as protected, otherwise users could call it directly.

namespace Something
{

    public sealed class OuterClass
    {
        private AbstractInnerClass inner;

        public OuterClass(AbstractInnerClass inner)
        {
            this.inner = inner;
        }

        public void MethodToBeCalled()
        {
            MustBeCalled();
            inner.CalledByOuter();
        }

        public void MustBeCalled()
        {
            //this must be called when AbstractMethod is invoked
            System.Console.WriteLine("OuterClass.MustBeCalled");
        }
    }

    public abstract class AbstractInnerClass
    {
        internal void CalledByOuter()
        {
            AbstractMethod();
        }

        protected abstract void AbstractMethod();
    }
}

public class ImplementInnerClass : Something.AbstractInnerClass
{
    protected override void AbstractMethod()
    {
        //when called, base.MustBeCalled() must be called.
        //how can i enforce this?
        System.Console.WriteLine("ImplementInnerClass.AbstractMethod");
    }

    public new void CalledByOuter()
    {
        System.Console.WriteLine("doesn't work");
    }
}
Nate