C# 失败的协变转换
C# Failing Covariant Cast
我正在尝试创建具有一系列实现的类似通用 table 工厂的东西。下面的示例是不言自明的,即使两个类型属性都标记为 '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>
的实例。这意味着,无论您从中得到什么 table,您都可以添加 SuperRows
,然后读取 SuperRows
。
然而,您的 ITableFactory<ITableRow, Table<ITableRow>>
声称它产生 Table<ITableRows>
-- table 人们可以添加 ITableRows
并从中读取 ITableRows
。
但您的实际 table 工厂生产 Table<SuperRow>
s -- 底层行存储是 SuperRow
。你不能让别人把任何旧的 ITableRow
放在那里!
这就是你的转换失败的原因。
如果去掉 "people can add rows to tables" 位就可以解决这个问题,并保证人们只能读取行。那么 Table
的行存储是否实际上是 SuperRow
并不重要,因为人们不能尝试将其他类型的行放在那里。
你通过使 Table<T>
协变来做到这一点。但是正如您所指出的, 类 不能是协变的,只能是接口。所以你需要一个 ITable<out T>
.
我正在尝试创建具有一系列实现的类似通用 table 工厂的东西。下面的示例是不言自明的,即使两个类型属性都标记为 '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>
的实例。这意味着,无论您从中得到什么 table,您都可以添加 SuperRows
,然后读取 SuperRows
。
然而,您的 ITableFactory<ITableRow, Table<ITableRow>>
声称它产生 Table<ITableRows>
-- table 人们可以添加 ITableRows
并从中读取 ITableRows
。
但您的实际 table 工厂生产 Table<SuperRow>
s -- 底层行存储是 SuperRow
。你不能让别人把任何旧的 ITableRow
放在那里!
这就是你的转换失败的原因。
如果去掉 "people can add rows to tables" 位就可以解决这个问题,并保证人们只能读取行。那么 Table
的行存储是否实际上是 SuperRow
并不重要,因为人们不能尝试将其他类型的行放在那里。
你通过使 Table<T>
协变来做到这一点。但是正如您所指出的, 类 不能是协变的,只能是接口。所以你需要一个 ITable<out T>
.