需要将一个通用类型转换为其接口

3

我创建了以下接口和类:

public interface IRecord
{
}
public class Person : IRecord
{
}
public class Company : IRecord
{
}
public class Contact : IRecord
{
}
public class Table<T> where T : IRecord
{
}

我还有一个用于管理表格的静态类。我希望能够根据 switch 语句获取特定的表格:

public class DataBase
{
    public static Table<Person> Persons { get; set; }
    public static Table<Contact> Contacts { get; set; }
    public static Table<Company> Companies { get; set; }

    public static Table<IRecord> GetTable(eDataType type)
    {
        switch (type)
        {
            case eDataType.company:
                return Companies;
            case eDataType.contact:
                return Contacts;
            case eDataType.person:
                return Persons;
        }
        return null;
    }
}

然而,所有的返回行都会抛出编译错误:
Cannot implicitly convert type 'Table<Company>' to 'Table<IRecord>'

我能修改我的代码以返回正确的表格吗?
2个回答

6
您不能这样做,因为一个Table<Company> 不是一个 Table<IRecord>,即使Company实现了IRecord。这是因为Table<T>不是协变的(类无法协变,只有接口和委托可以)。
为了说明原因,让我们假设您的Table<T>类具有一个Insert(T record)方法;如果您能将Table<Company>视为Table<IRecord>,那么它将允许您在表中插入PersonContact,这显然是不正确的。
现在,问题是,您打算如何使用返回的表?如果您只想读取它,您可以定义一个协变接口,如下所示:
public interface ITable<out T> where T : IRecord
{
}

然后使Table<T>实现此接口,并将GetTable更改为返回ITable<IRecord>而不是Table<IRecord>
请注意,接口只能在输出位置上具有T(即它不能具有以T作为参数的方法),否则将不允许协变。

3

解决这个问题的一种方法是添加一个非泛型基类。如果您想确保没有人尝试实例化它,甚至可以使其抽象

public abstract class TableBase 
{
}

然后你可以拥有以下内容:
public class Table<T> : TableBase where T : IRecord
{
}

现在这样就可以运行:

public static TableBase GetTable(eDataType type)
{
    switch (type)
    {
        case eDataType.company:
            return Companies;
        case eDataType.contact:
            return Contacts;
        case eDataType.person:
            return Persons;
    }
    return null;
}

谢谢,马特,这正是我在寻找的! - Francine DeGrood Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接