在不同子类的ArrayList中访问正确的函数

本文关键字:访问 函数 ArrayList 子类 | 更新日期: 2023-09-27 18:03:26

假设我有以下三个类:

父类

:

public class ParentClass {
    public void foo() {
        Debug.Log("Parent called!");
    }
}

第一个子类:

public class ChildOne : ParentClass {
    public new void foo() {
        Debug.Log("Child one called!");
    }
}

第二个子类:

public class ChildTwo : ParentClass {
    public new void foo() {
        Debug.Log("Child two called!");
    }
}

在第四个类中,我有一个包含多个childdone和ChildTwo对象的ArrayList。ArrayList不包含任何其他类型的对象。

如何访问子对象的foo()函数?

public class Example {
    public void someFunction() {
        //...
        ArrayList children = new ArrayList();
        children.add(new ChildOne());
        children.add(new ChildTwo());
        children[0].foo(); //here I want to call the foo() function of the ChildOne object
        children[1].foo(); //here I want to call the foo() function of the ChildTwo object
        //...
    }
}

转换到ParentClass不起作用,而且我不能转换到其中一个子类,因为我不知道每个元素的类型。

在不同子类的ArrayList中访问正确的函数

如果可以,可以使用多态性而不是隐藏父类的foo函数。

要实现这个结果,我们可以转换父类,使foo方法成为虚的,这样我们就可以在子类中重写它:
public class ParentClass {
    public virtual void foo() {
        Debug.Log("Parent called!");
    }
}
然后在子类中,用override关键字替换新的关键字:
public class ChildOne : ParentClass {
    public override void foo() {
        Debug.Log("Child one called!");
    }
}
public class ChildTwo : ParentClass {
    public override void foo() {
        Debug.Log("Child two called!");
    }
}

使用ArrayList,可以这样调用foo方法:

ArrayList children = new ArrayList();
children.Add(new ChildOne());
(children[0] as ParentClass).foo(); // will display "Child one called!"

请注意children[0]返回一个对象。你必须将这个对象强制转换为ParentClass才能调用foo方法。

我的最后一个建议是使用List而不是ArrayList。List是强类型的(你不需要强制转换任何东西),因为没有装箱/拆箱,所以速度要快一点。现在没有太多的理由(如果有的话)使用ArrayList。

var children = new List<ParentClass>();
children.Add(new ChildOne());
children[0].foo(); // will display "Child one called!"

带有反射:

var child = children[0];
Type childType = child.GetType();
MethodInfo mi = childType.GetMethod("foo");
mi.Invoke(child, new object[]{});

作为动力学态,最好的解决方案是使ParentClass.foo()虚化。但是,如果你不能修改父类,那么你就需要别的东西了。

作为反射的替代方法,您可以尝试这样做:

foreach (var child in children) {
    if (child is ChildOne) {
        ((ChildOne)child).foo();
    } else if (child is ChildTwo) {
        ((ChildTwo)child).foo();
    } else {
        // whatever you need to do to handle an unknown child
    }
}

正如Noob所指出的那样,对于许多子类来说,这可能是笨拙的。另一种选择是使用接口,如下所示:

public interface IFoo {
    void foo();
}
public class ChildOne : ParentClass, IFoo {
    public new void foo() {
        Debug.Log("Child one called!");
    }
}
public class ChildTwo : ParentClass, IFoo {
    public new void foo() {
        Debug.Log("Child two called!");
    }
}
然后

:

foreach (var child in children) {
    if (child is IFoo) {
        ((IFoo)child).foo();
    } else {
        // handle unknown child
    }
}