我有一个表控制器,我用于几个表(数据模型)。以下是它的简化版本:
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()
。我如何让这个工作?
答案 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接口。