需要将泛型转换为其接口

时间:2014-09-11 00:25:54

标签: c# generics interface

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

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 个答案:

答案 0 :(得分:6)

您无法做到这一点,因为Table<Company>不是Table<IRecord>,即使Company实现了IRecord。这是因为Table<T>不是covariant(类无论如何都不能协变,只有接口和代理可以)。

为了解释原因,我们假设您的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作为参数的方法),或者它赢了& #39; t被允许是协变的。

答案 1 :(得分:3)

处理此问题的一种方法是添加非泛型基类。如果你想确保没有人可以尝试实例化它,它甚至可以是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;
}