【问题标题】:Use abstract classes as function parameters [duplicate]使用抽象类作为函数参数[重复]
【发布时间】:2019-11-09 19:50:56
【问题描述】:

我需要帮助来理解抽象类的使用。我有一个名为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#


    【解决方案1】:

    List&lt;Building&gt;List&lt;WorldObject&gt; 的分配不兼容,因为那样你可以这样做

    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

    【讨论】:

      【解决方案2】:

      您可以使用泛型函数。

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

      正如其他答案所提到的,问题是List&lt;WorldObject&gt;List&lt;Building&gt; 不同。如果您想将List 传递给您的参数而不是IEnumerable,您可以使用一个通用函数,它采用TList,其中TWorldObject。现在T 已分配给BuildingList&lt;Building&gt; 是可以接受的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-02
        • 2011-03-16
        • 1970-01-01
        • 2018-10-12
        • 2012-03-08
        相关资源
        最近更新 更多