【问题标题】:Conversion not possible when using inheritance and generics [duplicate]使用继承和泛型时无法转换[重复]
【发布时间】:2021-10-31 15:10:45
【问题描述】:

这是我发布的第一个问题,所以当我遗漏了什么或做错了什么时,请告诉我。 :)

我尝试创建一个用于创建网格的通用类。 所以我从那个泛型类继承并传递所有需要的参数。由于某种原因,编译器无法解决我的不同类的继承问题,我不确定其背后的原因是什么,因为我并不真正习惯于继承中的泛型。

错误信息:

错误 CS1503 参数 1:无法从“GridXZ<BattleGridObject>”转换为“GridXZ<GridXZObject>”BattleGridSystem.cs 7

因此编译器无法将BattleGridObject 转换为GridXZObject。这对我来说很奇怪,因为BattleGridObject 继承自GridXZObject。那么我在这里遗漏的明显点是什么? 据我所知,BattleGridObject 应该被强制转换/转换(?)到他的基类 GridXZObject 中,没有任何问题。

BattleGridSystem.cs

public class BattleGridSystem : MonoBehaviour
{
    public BattleGrid Grid;

    private void Awake()
    {
        Grid = new BattleGrid(10, 10, 5, Vector3.zero, (grid, x, z) => new BattleGridObject(grid, x, z));
    }
}

BattleGrid.cs

public class BattleGrid : GridXZ<BattleGridObject>
{
    public BattleGrid(int width, int height, float cellSize, Vector3 originPosition, Func<GridXZ<BattleGridObject>, int, int, BattleGridObject> createGridObject) 
        : base(width, height, cellSize, originPosition, createGridObject)
    {

    }
}

BattleGridObject.cs

public class BattleGridObject : GridXZObject
{
    public BattleGridObject(GridXZ<GridXZObject> grid, int x, int z) : base(grid, x, z)
    {

    }
}

GridXZ.cs

public abstract class GridXZ<TGridXZObject> where TGridXZObject : GridXZObject
{
    public event EventHandler<OnGridXZObjectChangedEventArgs> OnGridObjectChanged;

    public readonly int Width;
    public readonly int Height;
    public readonly float CellSize;

    protected readonly Vector3 OriginPosition;
    protected readonly TGridXZObject[,] GridArray;

    public GridXZ(int width, int height, float cellSize, Vector3 originPosition, Func<GridXZ<TGridXZObject>, int, int, TGridXZObject> createGridObject)
    {
        Width = width;
        Height = height;
        CellSize = cellSize;

        OriginPosition = originPosition;
        GridArray = new TGridXZObject[width, height];

        for (var x = 0; x < GridArray.GetLength(0); x++)
        {
            for (var z = 0; z < GridArray.GetLength(1); z++)
            {
                GridArray[x, z] = createGridObject(this, x, z);
            }
        }
    }
}

GridXZObject.cs

public abstract class GridXZObject
{
    protected readonly GridXZ<GridXZObject> Grid;
    protected readonly int X;
    protected readonly int Z;

    public GridXZObject(GridXZ<GridXZObject> grid, int x, int z)
    {
        Grid = grid;
        X = x;
        Z = z;
    }

    public override string ToString()
    {
        return $"{X}, {Z}";
    }
}

OnGridXZObjectChangedEventArgs.cs

public class OnGridXZObjectChangedEventArgs : EventArgs
{
    public int X;
    public int Z;
}

【问题讨论】:

  • BattleGridObject 需要 GridXZ&lt;GridXZObject&gt;,但 lambda 工厂方法的参数是 GridXZ&lt;BattleGridObject&gt;。这些不是可分配的类型。
  • 我会尝试更改BattleGridObject 中的类型,但这仍然让我感到困惑,因为BattleGrid 继承了GridXZ&lt;GridXZObject&gt;BattleGridObject 继承了GridXZObject。此外,我确信在 BattleGridObject. 中调用基本构造时会导致另一个转换错误
  • @JeremyLakeman 好的,但是我更改了 BattleGridSystemBattleGridBattleGridObject 内部的类型,但我找不到可行的解决方案。您能否向我解释为什么这些类型不可分配?我似乎遗漏了一些关于泛型和继承的重要信息。
  • "因此编译器无法将 BattleGridObject 转换为 GridXZObject。" - 这不是编译器错误所说的。它说它无法从GridXZ&lt;BattleGridObject&gt; 转换为GridXZ&lt;GridXZObject&gt;。这根本不是一回事——就像“香蕉是水果”但“一堆香蕉”不是“水果碗”一样。 (您无法从 List&lt;Banana&gt; 转换为 List&lt;Fruit&gt;,因为您可以将 any 水果添加到 List&lt;Fruit&gt;,但您不能将苹果添加到 List&lt;Banana&gt;。)跨度>

标签: c# visual-studio unity3d generics inheritance


【解决方案1】:

好的。解决方案是为 Grid 和 GridObject 添加两个接口,并在抽象类中使用它们。这样编译器就知道如何在不同的类之间进行转换,并且智能感知会显示正确的数据类型。

我仍然不确定为什么最初的解决方案不起作用,但事实就是这样。

BattleGridSystem.cs

public class BattleGridSystem : MonoBehaviour
{
    public BattleGrid Grid;

    private void Awake()
    {
        Grid = new BattleGrid(10, 10, 5, Vector3.zero, (grid, x, z) => new BattleGridObject(grid, x, z));
    }
}

BattleGrid.cs

public class BattleGrid : GridXZ<BattleGridObject>
{
    public BattleGrid(int width, int height, float cellSize, Vector3 originPosition, Func<IGridXZ<IGridXZObject>, int, int, BattleGridObject> createGridObject) 
        : base(width, height, cellSize, originPosition, createGridObject)
    {
    }
}

BatleGridObject.cs

public class BattleGridObject : GridXZObject
{
    public BattleGridObject(IGridXZ<IGridXZObject> grid, int x, int z) 
        : base(grid, x, z)
    {
    }
}

IGridXZ.cs

public interface IGridXZ<out TGridXZObject> where TGridXZObject : IGridXZObject
{

}

GridXZ.cs

public abstract class GridXZ<TGridXZObject> : IGridXZ<TGridXZObject> where TGridXZObject : GridXZObject
{
    public event EventHandler<OnGridXZObjectChangedEventArgs> OnGridObjectChanged;

    public readonly int Width;
    public readonly int Height;
    public readonly float CellSize;

    protected readonly Vector3 OriginPosition;
    protected readonly TGridXZObject[,] GridArray;

    public GridXZ(int width, int height, float cellSize, Vector3 originPosition, Func<IGridXZ<IGridXZObject>, int, int, TGridXZObject> createGridObject)
    {
        Width = width;
        Height = height;
        CellSize = cellSize;

        OriginPosition = originPosition;
        GridArray = new TGridXZObject[width, height];

        for (var x = 0; x < GridArray.GetLength(0); x++)
        {
            for (var z = 0; z < GridArray.GetLength(1); z++)
            {
                GridArray[x, z] = createGridObject(this, x, z);
            }
        }
    }
}

IGridObject.cs

public interface IGridXZObject
{

}

GridXZObject.cs

public abstract class GridXZObject : IGridXZObject
{
    protected readonly IGridXZ<IGridXZObject> Grid;
    protected readonly int X;
    protected readonly int Z;

    public GridXZObject(IGridXZ<IGridXZObject> grid, int x, int z)
    {
        Grid = grid;
        X = x;
        Z = z;
    }

    public override string ToString()
    {
        return $"{X}, {Z}";
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-18
    • 1970-01-01
    相关资源
    最近更新 更多