使用抽象类作为函数参数

时间:2019-11-09 19:50:56

标签: c#

我需要帮助来理解抽象类的用法。我有一个名为WorldObject的抽象类:

public abstract class WorldObject
{
    public Vector3 position;
}

我有许多继承自此的类,例如BuildingTree

我想创建一种方法,该方法遍历List的{​​{1}},然后返回最接近我的方法。 我希望能够对所有类型的WorldObjects使用此方法,但无法使其正常工作:

WorldObjects

当我尝试将public List<Building> buildings = new List<Building>(); public List<Tree> trees= new List<Tree>(); private void GoToClosestBuilding() { var target = GetClosestWorldObject(buildings); //Error: Cannot convert building to WorldObject } Vector3 GetClosestWorldObject(List<WorldObject> objects) { //... } Building列表传递给我的方法时,它返回错误,无法在TreeBuilding之间转换,依此类推。

如何构造代码,使类似的代码行得通?

2 个答案:

答案 0 :(得分:6)

List<Building>List<WorldObject>的分配不兼容,因为那样您就可以这样做

List<WorldObject> worldObjects = buildings; // Not possible!
worldObjects.Add(tree); // Legal

worldObjects.Add(tree);是完全合法的。但是,由于worldObjects会引用建筑物列表,因此您不能将其添加为树!

但是,您可以将方法的签名更改为

Vector3 GetClosestWorldObject(IEnumerable<WorldObject> objects)
{
    ...
}

现在可以了

var target = GetClosestWorldObject(buildings);

因为可枚举被声明为

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

out关键字指出T仅出现在外位置,即作为返回值或外参数。这使类型成为协变。

另请参阅: -Covariance and Contravariance (C#) - Microsoft Docs

答案 1 :(得分:1)

您可以使用通用函数。

Vector3 GetClosestWorldObject<T>(List<T> objects) where T: WorldObject 
{
    // ...
}

其他答案提到的问题是List<WorldObject>List<Building>不同。如果要将List传递给参数而不是IEnumerable,则可以使用通用函数,该函数采用List中的T,其中TWorldObject。现在T已分配给BuildingList<Building>是可以接受的。