Search code examples
c#oopderived-classderived-types

Is this 'pattern' ok or is there a better method?


I have several classes in my app (just a fragment):

public abstract class Element {...}

public abstract class Program : Element
{
    ...

    public void SpecificProgramCall();
}

When I know a variable patch is of subtype Program I use:

((Program) element).SpecificProgramCall();

or better:

var patch = patch as Program;
Debug.Assert(patch != null);
patch.SpecificProgramCall();

When I don't know if it is a program:

var patch = patch as (Program);
if (patch != null)
{
    patch.SpecificProgramCall();
}

However, my code is (will be) full of these constructs. Is there a better way to implement this?

Example:

var usedProgramBank = ((SetListSlot) setListSlot).UsedPatch.Parent as ProgramBank;
var key = new Tuple<ProgramBank, Program>(usedProgramBank, ((SetListSlot) setListSlot).UsedPatch as Program);
if (_dict.ContainsKey(key) && !_dict[key].Contains(setListSlot))
{
    _dict[key].Add(setListSlot);
}

Solution

  • Without more specific information about these types (including their semantics, your access to their code, etc), I'd say that this pattern is generally a candidate for dynamic dispatch. For example:

    public abstract class Element
    {
        public virtual void MaybeSpecificCall()
        {
            // nothing in most cases
        }
    }
    
    public abstract class Program : Element
    {
        public override void MaybeSpecificCall()
        {
            base.MaybeSpecificCall();
    
            // but in this specific case, do something
            SpecificProgramCall(); 
        }
    
        public void SpecificProgramCall() { /* ... */ }
    }
    

    Then you can just do patch.MaybeSpecificCall() at the call spots and let the dynamic dispatch mechanism decide between doing something and doing nothing.


    Alternatively, if you don't want to mess with the base class and you're only interested in not seeing the 'ugly' type checks, then a helper method could do the trick:

    static void IfProgram(this Element element, Action<Program> action)
    {
        var program = element as Program;
        if(program != null) action.Invoke(program);
    }
    

    And, again, you call it using patch.IfProgram(x => x.SpecificProgramCall()). I personally like lambdas, but whether they're ugly for this job is up to you.