我有一个表控制器,用于多个表(数据模型)。这是它的简化版本:
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);
它告诉我我无法将 Table(A,B,C) 转换为 TableBase 类型,出于某种原因,将 base 用作控制器类中的类型会吓坏一切。我不认为这会导致差异问题,但似乎是。我想做的只是在循环中的每个控制器上调用Synchronize()
。我如何让它工作?
如果需要在其他不兼容的类型中调用常用方法,则可以定义一个公开需要调用的功能的接口。
在此代码示例中,我添加了一个新的接口ICanSync
,该接口具有来自Controller<T>
的方法签名匹配Synchronize()
,并修改了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
,可以声明协变或逆变接口。