C#失败的协变演员阵容



我正在尝试创建一个类似于具有一系列实现的通用表工厂的东西。下面的示例是不言自明的,即使两个类型属性都标记为"out",最后的强制转换也不起作用。我想,问题是Table不是一个接口,这打破了强制转换。但它并不是真正的接口,尤其不是协变的。有什么想法吗?绝对不想用反射来使用方法。

interface ITableRow { }
class Table<T> where T : ITableRow { }
interface ITableFactory<out TRow, out TTable>
where TRow : ITableRow
where TTable : Table<TRow>
{
TTable CreateTable();
}
// example implementation:
class SuperRow : ITableRow { }
class SuperTableFactory : ITableFactory<SuperRow, Table<SuperRow>>
{
public Table<SuperRow> CreateTable() { throw new NotImplementedException(); }
}
// run:
class VarianceTest
{
public static void Test()
{
var factory = Activator.CreateInstance(Type.GetType("Snippets.Var.SuperTableFactory"));
var casted = (ITableFactory<ITableRow, Table<ITableRow>>) factory; // cast fails
}
}

您的SuperTableFactory声称生成Table<SuperRow>的实例。这意味着,无论从中得到什么表,都可以添加SuperRows,并读取SuperRows

然而,您的ITableFactory<ITableRow, Table<ITableRow>>声称它生成Table<ITableRows>——人们可以将ITableRows添加到表中,也可以从中读取ITableRows

但是实际的表工厂生产Table<SuperRow>s——底层的行存储是SuperRow。你不能让别人在里面放任何旧的ITableRow

这就是你的演员阵容失败的原因。

如果去掉"人们可以向表中添加行"这一点,并承诺人们只能读取行,就可以绕过这一点。那么Table的行存储是否真的是SuperRow就无关紧要了,因为人们不能尝试在其中放入其他类型的行。

通过使Table<T>协变来实现这一点。但正如您所指出的,类不能是协变的,只能是接口。所以你需要一个ITable<out T>

相关内容

  • 没有找到相关文章

最新更新