编辑:已更新,以包含实际代码。
我遇到了一些自定义通用接口的问题,我不完全确定要做什么。我得到的错误是:
无法从
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())
{
// ...
}
}
}
这类似于this stack overflow question,但有点不同。我尝试实现了一个界面IMap
以及IMap<T> : IMap where T : ICell
,但我也遇到了问题。
最后,我不确定这是否可以通过co / contravariance解决,但我使用的是C#3.0,这对我来说是不合适的(除非切换版本是唯一的方法)。
我认为使用隐式/直接演员会没问题吗?
_fieldOfView = new FieldOfView(this as IMap<ICell>); // or
_fieldOfView = new FieldOfView((IMap<ICell>)this);
但如果有更好的方法,我想这样做。当我Map
向IMap<ICell>
投降时,Resharper会给我一个警告:
<击>
可疑演员:解决方案中没有从Map
和IMap<ICell>
继承的类型。
EDIT2:看起来就像两个演员都没有工作。我决定让Map从IMap派生出来,只需在代码中需要的地方创建Cell对象。
感谢@Rob和@ MK87的帮助!
答案 0 :(得分:2)
否,IMap<Cell>
不与IMap<ICell>
相同,所以这一行:
_fieldOfView = new FieldOfView(this as IMap<ICell>);
将始终将 null 作为参数传递。
是,这绝对可以通过方差来解决。
例如,您可以:
IEnumerable<object> list = new List<string>();
由于list
为IEnumerable<
out
T>
,这意味着每个IEnumerable<TT>
TT
派生的T
来自list
的{{1}}的有效值。因此List
不必是object
,它可以是任何派生类型。
但是因为你不能使用方差,我们需要另一个黑客。
可能的解决方案:不是从Map
派生IMap<Cell>
,而是从IMap<ICell>
派生。您只需更正某些点,例如GetCell()
的返回类型必须变为ICell
而不是Cell
。对你来说可行吗?