将抽象类用作函数参数

问题描述 投票:2回答:3

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

public abstract class WorldObject
{
    public Vector3 position;
}

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

我想创建一个循环通过ListWorldObjects的方法,并向我返回最接近的方法。我希望能够对我的所有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)
{
    //...
}

[当我尝试将BuildingTree列表传递给我的方法时,它返回错误,无法在BuildingWorldObject之间进行转换,依此类推。

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

c# architecture
3个回答
3
投票

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
投票

您可以使用通用函数。

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

0
投票

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

worldObjects.Add(tree);

这是完全合法的。但是,由于该列表引用了建筑物列表,因此您不能将其添加为树!

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

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

现在,这有效

var target = GetClosestWorldObject(buildings);

因为可枚举被声明为

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

out的关键字T仅出现在外位置,即作为返回值或out参数。

© www.soinside.com 2019 - 2024. All rights reserved.