泛型类型转换问题:Grid与PathNode实例化冲突求解
解决方案:利用泛型协变接口解决类型转换问题
核心问题分析
Grid<PathNode> 和 Grid<IPathNode> 是两个无继承关系的独立泛型类型,C# 默认不允许直接强制转换。要解决这个问题,我们可以通过协变泛型接口实现类型兼容,同时不需要给PathNode添加泛型参数。
具体修改步骤
1. 定义协变接口 IGrid<out T>
创建支持协变的接口,包含Grid<T>的所有公共只读属性(协变要求T只能作为输出,不能作为输入参数,当前Grid<T>的属性均为只读,符合要求):
public interface IGrid<out T> { int Width { get; } int Height { get; } float CellSize { get; } Vector2 GridOffset { get; } T[,] GridObjects { get; } }
2. 让 Grid<T> 实现该接口
修改Grid<T>类,实现IGrid<T>接口:
public class Grid<T> : IGrid<T> { public int Width { get; } public int Height { get; } public float CellSize { get; } public Vector2 GridOffset { get; } public T[,] GridObjects { get; } public Grid(int width, int height, float cellSize, Vector3 gridOffset, Func<Grid<T>, int, int, T> createGridObjectMethod) { this.Width = width; this.Height = height; this.CellSize = cellSize; this.GridOffset = gridOffset; GridObjects = new T[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { GridObjects[x, y] = createGridObjectMethod(this, x, y); } } } }
3. 修改 PathNode 的构造函数参数
将构造函数的Grid<IPathNode>参数改为IGrid<IPathNode>,这样可以接受任何实现了IGrid<IPathNode>的类型(包括Grid<PathNode>,因为协变允许IGrid<PathNode>隐式转换为IGrid<IPathNode>):
public class PathNode : IPathNode { private readonly IGrid<IPathNode> grid; public int X { get; } public int Y { get; } public PathNode PreviousNode; public PathNode(IGrid<IPathNode> grid, int x, int y) { this.grid = grid; this.X = x; this.Y = y; } public PathNode GetPathNode() { return this; } }
4. 实例化 Grid<PathNode>
现在可以直接创建实例,无需强制转换:
Grid<PathNode> grid = new Grid<PathNode>(10, 10, 1, new Vector3(-5, -5, 0), (g, x, y) => { return new PathNode(g, x, y); });
方案原理
协变接口IGrid<out T>中的out关键字表明T是协变类型,允许将IGrid<Derived>转换为IGrid<Base>(只要Derived继承自Base)。Grid<PathNode>实现了IGrid<PathNode>,而PathNode实现了IPathNode,因此IGrid<PathNode>可以隐式转换为IGrid<IPathNode>,完美匹配PathNode构造函数的参数要求。
内容的提问来源于stack exchange,提问作者Axvemi
相关产品推荐
相关产品推荐

