如何使用不兼容类型的对象集合?

时间:2018-04-05 19:11:35

标签: c# list covariance

我有一个表控制器,我用于几个表(数据模型)。以下是它的简化版本:

public abstract class TableBase
    {
        public virtual void TableName()
        {
            Console.WriteLine("I am Table: " + this.GetType().Name);
        }
    }

public class TableA : TableBase
    {
    }

public class TableB : TableBase
    {
    }

public class TableC : TableBase
    {
    }

public class Controller<T> where T : TableBase
    {
        public Controller(T table)
        {
            table.TableName();
        }

        public void Synchronize();
    }

然后我基本上这样使用它:

Controller<TableA> Controller1 = new Controller<TableA>(new TableA());
Controller<TableB> Controller2 = new Controller<TableB>(new TableB());
Controller<TableC> Controller3 = new Controller<TableC>(new TableC());

一切都很轻松但是当我想将控制器添加到控制器列表时问题出现了:

List<Controller<TableBase>> ControllerList = new List<Controller<TableBase>>();
ControllerList.Add(Controller1);
ControllerList.Add(Controller2);
ControllerList.Add(Controller3);

它告诉我,我无法将表(A,B,C)转换为TableBase的类型,出于某种原因,使用base作为控制器类中的类型会使一切都变得怪异。我不认为这会引起差异问题,但似乎是。我想要做的就是在循环中在每个控制器上调用Synchronize()。我如何让这个工作?

1 个答案:

答案 0 :(得分:0)

如果需要以其他不兼容的类型调用公共方法,则可以定义一个公开您需要调用的功能的接口。

在此代码示例中,我添加了一个新接口ICanSync,其Synchronize()的方法签名与Controller<T>匹配,并修改Controller<T>以实现新接口。这意味着您可以创建List<ICanSync>并添加具有不兼容泛型类型的控制器。

// new interface to use
public interface ICanSync
{
    void Synchronize();
}

public abstract class TableBase
{
    public virtual void TableName()
    {
        Console.WriteLine("I am Table: " + this.GetType().Name);
    }
}

public class TableA : TableBase
{
}

public class TableB : TableBase
{
}

public class TableC : TableBase
{
}

public class Controller<T> : ICanSync where T : TableBase
{

    private TableBase _t;

    public Controller(T table)
    {
        _t = table;
    }

    public void Synchronize()
    {
        _t.TableName();
    }
}

您可以声明List<ICanSync>并致电Synchronize()

Controller<TableA> Controller1 = new Controller<TableA>(new TableA());
Controller<TableB> Controller2 = new Controller<TableB>(new TableB());
Controller<TableC> Controller3 = new Controller<TableC>(new TableC());

List<ICanSync> ControllerList = new List<ICanSync> {Controller1, Controller2, Controller3};

foreach (var controller in ControllerList) 
{
    controller.Synchronize();
}

这是类型安全的,因为ICanSync自然与其自身实例兼容。如果您需要使用T的更丰富的常用功能,则可以声明covariant or contravariant接口。