C#调用函数基于对象的子类型

时间:2022-02-17 21:36:20

I am confused by C# right now.

我现在很困惑C#。

I have a bunch of classes, say A, B, and C, which all derive from class "Parent". I have a function which takes an argument of type Parent, and depending on which child class the object it is called with is, I want it to call a different method.

我有一堆类,比如A,B和C,它们都来自“Parent”类。我有一个函数,它接受类型为Parent的参数,并且根据调用它的对象是哪个子类,我希望它调用另一个方法。

Currently, I am thinking using a dictionary mapping types to delegates, but that seems silly, though it is all I can come up with at the moment.

目前,我正在考虑使用字典映射类型代表委托,但这看起来很愚蠢,尽管我现在可以想出来。

The problem is that when I am in the function, I only know that it is of type Parent, and I can use GetType to get which child class I have, which would allow the dictionary. Otherwise I would probably use function overloading.

问题是当我在函数中时,我只知道它是Parent类型,我可以使用GetType来获取我拥有的子类,这将允许字典。否则我可能会使用函数重载。

Really typecasting seems like the best method, allowing me to use function overloading, which would be much less verbose, but I don't know how I could do it or if it would work at all.

真正的类型转换似乎是最好的方法,允许我使用函数重载,这将不那么冗长,但我不知道我是如何做到的,或者它是否会起作用。

Any reccomendations?

4 个解决方案

#1


Overloading is the correct way

重载是正确的方法

public void DoWork(Parent obj)
{
   if(obj is A)
     Foo((A)obj);

   else if(obj is B)
     Foo((B)obj);

   else
    Foo(obj);
}

public void Foo(Parent obj)
{
  //Do something for parent
}

public void Foo(A obj)
{
  //Do something for A
}

public void Foo(B obj)
{
  //Do something for B
}

or if you don't want to explicitly cast the object for each type you could use reflection like this:

或者如果您不想为每种类型显式地转换对象,您可以使用这样的反射:

Bar methodObject = new Bar();
MethodInfo method = methodObject.GetType().GetMethod(
            "Foo", new Type[] { obj.GetType()});

method.Invoke(methodObject, new object[]{obj});

#2


Do the methods all share the same signature? If so, make it a virtual (potentially abstract) method in the parent class:

这些方法都共享相同的签名吗?如果是这样,请将其设置为父类中的虚拟(可能是抽象的)方法:

using System;

public abstract class Parent
{
    public abstract void DoSomething();
}

public class A : Parent
{
    public override void DoSomething()
    {
        Console.WriteLine("A.DoSomething()");
    }
}

public class B : Parent
{
    public override void DoSomething()
    {
        Console.WriteLine("B.DoSomething()");
    }
}

public class Test
{
    static void Main()
    {
        Parent a = new A();
        Parent b = new B();
        a.DoSomething();
        b.DoSomething();
    }
}

If this isn't suitable then double dispatch may be suitable, but I'd really need to know more about the situation... it could be that changing some part of the existing design would work better.

如果这不合适,那么双重发送可能是合适的,但我真的需要了解更多情况......可能会改变现有设计的某些部分会更好。

#3


This seems like a perfect use for the visitor pattern, if you can't add a virtual method to Parent, and override in A,B and C

如果您无法向Parent添加虚拟方法,并在A,B和C中覆盖,这似乎是访问者模式的完美用途

#4


Is the name of the method different? Or is it a different implementation of the same method?

该方法的名称是否不同?或者它是同一方法的不同实现?

If the name of the method is the same, you can use override. Additionally, if there will only ever be a child method, the parent method should be marked abstract.

如果方法的名称相同,则可以使用override。此外,如果只有一个子方法,则父方法应标记为抽象。

EDIT: with code...

编辑:用代码......

public abstract class parentClass
{
    //...other stuff...
    protected abstract void doSomething(); //or use virtual instead of abstract and give the method a body
}

public class childClass : parentClass
{
    //...other stuff...
    protected override void doSomething()
    {
       //...do something
    }
}

#1


Overloading is the correct way

重载是正确的方法

public void DoWork(Parent obj)
{
   if(obj is A)
     Foo((A)obj);

   else if(obj is B)
     Foo((B)obj);

   else
    Foo(obj);
}

public void Foo(Parent obj)
{
  //Do something for parent
}

public void Foo(A obj)
{
  //Do something for A
}

public void Foo(B obj)
{
  //Do something for B
}

or if you don't want to explicitly cast the object for each type you could use reflection like this:

或者如果您不想为每种类型显式地转换对象,您可以使用这样的反射:

Bar methodObject = new Bar();
MethodInfo method = methodObject.GetType().GetMethod(
            "Foo", new Type[] { obj.GetType()});

method.Invoke(methodObject, new object[]{obj});

#2


Do the methods all share the same signature? If so, make it a virtual (potentially abstract) method in the parent class:

这些方法都共享相同的签名吗?如果是这样,请将其设置为父类中的虚拟(可能是抽象的)方法:

using System;

public abstract class Parent
{
    public abstract void DoSomething();
}

public class A : Parent
{
    public override void DoSomething()
    {
        Console.WriteLine("A.DoSomething()");
    }
}

public class B : Parent
{
    public override void DoSomething()
    {
        Console.WriteLine("B.DoSomething()");
    }
}

public class Test
{
    static void Main()
    {
        Parent a = new A();
        Parent b = new B();
        a.DoSomething();
        b.DoSomething();
    }
}

If this isn't suitable then double dispatch may be suitable, but I'd really need to know more about the situation... it could be that changing some part of the existing design would work better.

如果这不合适,那么双重发送可能是合适的,但我真的需要了解更多情况......可能会改变现有设计的某些部分会更好。

#3


This seems like a perfect use for the visitor pattern, if you can't add a virtual method to Parent, and override in A,B and C

如果您无法向Parent添加虚拟方法,并在A,B和C中覆盖,这似乎是访问者模式的完美用途

#4


Is the name of the method different? Or is it a different implementation of the same method?

该方法的名称是否不同?或者它是同一方法的不同实现?

If the name of the method is the same, you can use override. Additionally, if there will only ever be a child method, the parent method should be marked abstract.

如果方法的名称相同,则可以使用override。此外,如果只有一个子方法,则父方法应标记为抽象。

EDIT: with code...

编辑:用代码......

public abstract class parentClass
{
    //...other stuff...
    protected abstract void doSomething(); //or use virtual instead of abstract and give the method a body
}

public class childClass : parentClass
{
    //...other stuff...
    protected override void doSomething()
    {
       //...do something
    }
}