无法从类转换为通用接口

时间:2016-05-27 01:47:22

标签: c# generics interface contravariance

编辑:已更新,以包含实际代码。

我遇到了一些自定义通用接口的问题,我不完全确定要做什么。我得到的错误是:

  

无法从Map转换为IMap<ICell>

当我尝试将Map作为参数传递给接受IMap<ICell>的方法时,会弹出该错误。我在下面粘贴了示例代码。需要明确的是,FieldOfView不会使用ICellIMap中尚未定义的任何内容。

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);

但如果有更好的方法,我想这样做。当我MapIMap<ICell>投降时,Resharper会给我一个警告:

<击>   

可疑演员:解决方案中没有从MapIMap<ICell>继承的类型。

EDIT2:看起来就像两个演员都没有工作。我决定让Map从IMap派生出来,只需在代码中需要的地方创建Cell对象。

感谢@Rob和@ MK87的帮助!

1 个答案:

答案 0 :(得分:2)

IMap<Cell> IMap<ICell>相同,所以这一行:

_fieldOfView = new FieldOfView(this as IMap<ICell>);

将始终将 null 作为参数传递。

,这绝对可以通过方差来解决。

例如,您可以:

IEnumerable<object> list = new List<string>();

由于listIEnumerable< out T>,这意味着每个IEnumerable<TT> TT派生的T来自list的{​​{1}}的有效值。因此List不必是object,它可以是任何派生类型。

但是因为你不能使用方差,我们需要另一个黑客。

可能的解决方案:不是从Map派生IMap<Cell>,而是从IMap<ICell> 派生。您只需更正某些点,例如GetCell()的返回类型必须变为ICell而不是Cell。对你来说可行吗?