需要将泛型转换为其接口

本文关键字:接口 转换 泛型 | 更新日期: 2023-09-27 18:21:30

我创建了一个接口和类,如下所示:

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

我可以修改我的代码以返回正确的表吗?

需要将泛型转换为其接口

您不能这样做,因为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作为参数的方法),或者它不允许是协变的。

处理此问题的一种方法是添加一个非泛型基类。如果你想确保没有人可以尝试实例化它,它甚至可以是abstract

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