views:

183

answers:

4

When I call the EntryPoint with a parameter of type TemplateA, I always receive an exception, since the first overload is always called.
What I expected to happen is that the most specific method (second overload) will be called due to dynamic binding.
Any ideas why?

private object _obj;
    public void EntryPoint(object p)
    {
        myFunc(p);
    }

    //first overload
    private void myFunc(object container)
    {
        throw new NotImplementedException();
    }

    //second overload
    private void myFunc(TemplateA template)
    {
        _obj = new ObjTypeA(template);
    }

    //third overload
    private void myFunc(TemplateB template)
    {
        _obj = new ObjTypeB(template);
    }
+4  A: 

What I expected to happen is that the most specific method (second overload) will be called due to dynamic binding.

Where do you see dynamic binding here? The static type of the variable is object. Unless you call a virtual method on it directly, no dynamic dispatch is going to happen. The overload is completely statically resolved at compile time.

Eric Lippert has a related blog entry on this: Double Your Dispatch, Double Your Fun.

Mehrdad Afshari
+2  A: 

When you call EntryPoint() with a parameter of type TemplateA, it is cast to an object. Therefore, the subsequent statically bound call to myFunc(p) takes place with a parameter of type object.

Mitch Wheat
A: 

I think in the EntryPoint context the compiler knows first overload should be called as it is static binding not dynamic

Ahmed Said
+1  A: 

You will be able to do this in C# 4.0 if you use dynamic instead of object. Download the Visual Studio 2010 Beta if you want to give it a try. Until then, the compiler chooses exactly which method to call based on the parameter's compile-time types.

It's not clear from your question whether you know about ordinary single-dispatch polymorphism, as it would solve your example problem.

class TemplateBase
{
    public virtual object MyFunc()
    {
        throw new NotImplementedException();
    }
}

class TemplateA : TemplateBase
{
    public override object MyFunc()
    {
        return new ObjTypeA(this);
    }
}

class TemplateB : TemplateBase
{
    public override object MyFunc()
    {
        return new ObjTypeB(this);
    }
}

And elsewhere:

private object _obj;

public void EntryPoint(TemplateBase p)
{
    _obj = p.MyFunc();
}

There are alternatives for when you can't modify the TemplateN classes. The simplest would be for the EntryPoint method to have access to a Dictionary mapping from Type to some delegate.

Dictionary<Type, Func<object, object>> _myFuncs;

_myFuncs.Add(typeof(TemplateA), o => new ObjTypeA((TemplateA)o));
_myFuncs.Add(typeof(TemplateB), o => new ObjTypeB((TemplateA)o));

It could then look up the delegate to execute for the type of object passed to it.

Func<object, object> f = _myFuncs[p.GetType()];
_obj = f(p);

But you need to take care over inheritance hierarchies if you want to mimic the exact way virtual functions work.

Daniel Earwicker