How do I dispatch to a method based on a parameter's runtime type in C# < 4?

喜你入骨 提交于 2020-01-02 05:25:34

问题


I have an object o which guaranteed at runtime to be one of three types A, B, or C, all of which implement a common interface I. I can control I, but not A, B, or C. (Thus I could use an empty marker interface, or somehow take advantage of the similarities in the types by using the interface, but I can't add new methods or change existing ones in the types.)

I also have a series of methods MethodA, MethodB, and MethodC. The runtime type of o is looked up and is then used as a parameter to these methods.

public void MethodA(A a) { ... }
public void MethodB(B b) { ... }
public void MethodC(C c) { ... }

Using this strategy, right now a check has to be performed on the type of o to determine which method should be invoked. Instead, I would like to simply have three overloaded methods:

public void Method(A a) { ... } // these are all overloads of each other
public void Method(B b) { ... }
public void Method(C c) { ... }

Now I'm letting C# do the dispatch instead of doing it manually myself. Can this be done? The naive straightforward approach doesn't work, of course:

Cannot resolve method 'Method(object)'. Candidates are:

  • void Method(A)
  • void Method(B)
  • void Method(C)

回答1:


How about something like this?

private Dictionary<Type, Action<I>> _mapping = new Dictionary<Type, Action<I>>
{ 
  { typeof(A), i => MethodA(i as A)},
  { typeof(B), i => MethodB(i as B)},
  { typeof(C), i => MethodC(i as C)},
};

private void ExecuteBasedOnType(object value)
{
    if(_mapping.ContainsKey(value.GetType()))
       _mapping(value.GetType())(value as I);
}



回答2:


If you can refactor this, move the method to the interface and have each class has its implementation:

I i = o as I;
i.Method();



回答3:


If the 3 class A, B and C implements the interface I you should do nothing. It's the runtime that choose the right method for you:

A a = new A();
class.Method(a); // will calll Method(A a)

B b = new B();
class.Method(b); // will call Method(B b)



回答4:


I'm not 100% sure if this will work in your scenario, but it sounds like you might be able to use partial classes:

public interface IMethodCallable
{
    public void Method();
}

public partial class A : IMethodCallable
{
    public void Method()
    {
        ....
    }
}

then for the usage:

object o = getObject(); // we know this is A, B or C
((IMethodCallable)o).Method();



回答5:


Preseumably O is declared as type/interface I then instantiated as either a b or c. The way to do it would be to have a single public method the took a param of type I and then do your logic within that method e.g. call private method A B or C.

Reading your edited post, o is of type object, remember to be clear when you take about an object becuase as well as being a c# type it is a generic oop term for an instance of a class.

Why are you declaring it as an object, rather than an i, might it be something else later?

If so to use your overloaded methods you would have to unbox it before calling the method. e.g.

if (o.GetType() == typeof(a))
{
   oa = (a)o;
   Method(oa);
}
else if(o.GetType() == typeof(b))
{
    ...
}

Etc.

Alternatively if you made the method take a paramater of type i you could do something like:

i oi = (i)o;
Method(oi);

But you would still need to do something like the the first example within your public method.



来源:https://stackoverflow.com/questions/2818436/how-do-i-dispatch-to-a-method-based-on-a-parameters-runtime-type-in-c-sharp-4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!