简体   繁体   English

C# 协变转换失败

[英]C# Failing Covariant Cast

I'm trying to create something like a generic table factory with a range of implementations.我正在尝试创建具有一系列实现的通用表工厂之类的东西。 Example below is self explanatory, and the cast in the end isn't working even though both type attributes marked as 'out'.下面的示例是不言自明的,即使两个类型属性都标记为“out”,最终的转换也不起作用。 I suppose, the issue is that Table isn't an interface and this breaks the cast.我想,问题是 Table 不是一个接口,这会破坏演员阵容。 But it shuldn't really be interface and especially not covariant.但它不应该是真正的接口,尤其是不是协变的。 Any ideas how to cast it properly?任何想法如何正确地投射它? Definitely don't want to use reflection to use methods.绝对不想用反射来使用方法。

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
    }
}

Your SuperTableFactory claims to produce instances of Table<SuperRow> .您的SuperTableFactory声称会生成Table<SuperRow>的实例。 That means, whatever table you get back from it, you can add SuperRows , and read SuperRows .这意味着,无论您从中获得什么表,您都可以添加SuperRows并读取SuperRows

However, your ITableFactory<ITableRow, Table<ITableRow>> claims that it produces Table<ITableRows> -- tables that people can add ITableRows to and read ITableRows from.但是,您的ITableFactory<ITableRow, Table<ITableRow>>声称它生成Table<ITableRows> - 人们可以将ITableRows添加到并从中读取ITableRows的表。

But your actual table factory produces Table<SuperRow> s -- the underlying row storage is SuperRow .但是您的实际表工厂会生成Table<SuperRow> ——底层的行存储是SuperRow You can't let someone put any old ITableRow in there!你不能让别人把任何旧的ITableRow放在那里!

That's why your cast is failing.这就是你的演员失败的原因。

You can get around this if you get rid of the "people can add rows to tables" bit, and promise that people can only ever read rows.如果您摆脱“人们可以向表中添加行”位,以及人们只能读取行的 promise,您就可以解决这个问题。 Then it doesn't matter whether a Table 's row storage is actually SuperRow , as people can't try and put other types of row in there.那么Table的行存储是否实际上是SuperRow并不重要,因为人们无法尝试将其他类型的行放入其中。

You do this by making Table<T> covariant.您可以通过使Table<T>协变来做到这一点。 But as you noted, classes can't be covariant, only interfaces.但是正如您所指出的,类不能是协变的,只能是接口。 So you'll need an ITable<out T> .所以你需要一个ITable<out T>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM