编辑:已更新以包含实际代码
我遇到了一些自定义通用接口的问题,我不完全确定该怎么办。我得到的错误是:
无法从
Map
转换为IMap<ICell>
当我试图将Map
作为参数传递给接受IMap<ICell>
的方法时,会弹出该错误。我在下面粘贴了示例代码。需要明确的是,FieldOfView
没有使用ICell
或IMap
中未定义的任何内容。
public class Map : IMap<Cell>
{
private FieldOfView _fieldOfView;
public int Width { get; }
public int Height { get; }
public Map(int width, int height)
{
Width = width;
Height = height;
_fieldOfView = new FieldOfView(this as IMap<ICell>);
_fieldOfView = new FieldOfView((IMap<ICell>)this);
}
public IEnumerable<Cell> GetAllCells()
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
yield return GetCell(x, y);
}
}
}
public Cell GetCell(int x, int y)
{
return new Cell(x, y);
}
public void Copy(IMap<Cell> sourceMap)
{
// ...
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var cell in GetAllCells())
{
sb.Append(cell.ToString());
}
return sb.ToString();
}
}
public interface IMap<T> where T : ICell
{
int Width { get; }
int Height { get; }
IEnumerable<T> GetAllCells();
T GetCell(int x, int y);
void Copy(IMap<T> sourceMap);
}
public class Cell : ICell
{
public int X { get; }
public int Y { get; }
public Cell(int x, int y)
{
X = x;
Y = Y;
}
public override string ToString()
{
return "overloaded";
}
}
public interface ICell
{
int X { get; }
int Y { get; }
}
public class FieldOfView
{
private readonly IMap<ICell> _map;
public FieldOfView(IMap<ICell> map)
{
_map = map;
}
public void DoStuff()
{
foreach (var cell in _map.GetAllCells())
{
// ...
}
}
}
这与这个堆栈溢出问题类似,但有点不同。我尝试实现接口IMap
和IMap<T> : IMap where T : ICell
,但也遇到了问题。
最后,我不确定这是否可以通过协变/逆变来解决,但我使用的是C#3.0,所以这对我来说是不可能的(除非切换版本是唯一的方法)。
我认为用隐式/直接演员阵容可以吗?
_fieldOfView = new FieldOfView(this as IMap<ICell>); // or
_fieldOfView = new FieldOfView((IMap<ICell>)this);
但如果有更好的方法,我愿意这样做。当我将Map
转换为IMap<ICell>
时,Resharper确实向我发出了警告:
可疑强制转换:解决方案中没有从
Map
和IMap<ICell>
继承的类型
第2版:看起来两个演员阵容都不起作用我决定让Map从IMap派生,只在代码中需要的地方创建Cell对象。
感谢@Rob和@MK87的帮助!
否,IMap<Cell>
是而不是与IMap<ICell>
相同,因此此行:
_fieldOfView = new FieldOfView(this as IMap<ICell>);
将始终传递null作为参数。
是,这肯定是可以用方差解决的。
例如,您可以有:
IEnumerable<object> list = new List<string>();
由于list
是IEnumerable<
out
T>
,这意味着从T
导出的每个具有TT
的IEnumerable<TT>
都是list
的有效值。因此List
不必是object
,它可以是任何派生类型。
但因为你不能使用方差,我们需要另一个破解。
可能的解决方案:不是从IMap<Cell>
派生Map
,而是从IMap<ICell>
派生。。您只需要更正一些点,例如GetCell()
的返回类型必须变为ICell
,而不是Cell
。这对你来说可行吗?