c# - 泛型类约束,其中 <T> 是约束泛型类的类型

标签 c# generics model-view-controller unity3d

也许不是最准确的标题,但有点难以描述;也许你们可以帮我解决这个问题?我正在使用 MVC 格式编写游戏,我希望每个基类( Controller 、模型和 View )都引用它们的附带功能,形成一种三角形(即模型引用 Controller 定义它,以及引用它的 View 等。)这些类中的大部分看起来像这样:

public class Model {
  public Controller controller;
  public View view;

  public void Connect (Controller controller, View view) {
    this.controller = controller;
    this.view = view; 
  }
}

这没问题,但每当我打算启动 ChildModel 的 Controller 时,我都需要转换为适当的 ChildController 以获得正确的版本。我可以制作一个实用程序方法/getter 来获取适当转换的项目,但我不想为每个子类重写这段代码。我以为我可以通过使基类通用化来解决这个问题,但现在我遇到了一个问题,新的通用类需要引用试图定义它们的类,因此:

public class Model<V, C> where V : View<?, C> where C : Controller<?, V> {
  public Controller<?, V> controller;
  public View<?, C> view;

  public void Connect (Controller<?, V> controller, View<?, C> view) {
    this.controller = controller;
    this.view = view; 
  }
}

如您所见,这在基类中很快就会变得困惑。我不知道要为试图定义约束的模型放置什么符号(引用上面的示例)。将“模型”放入问号似乎也无法编译,因为我遇到了一个 hell 般的装箱转换问题。

有没有一种方法可以完成我所追求的,或者我只是想在这里变得太聪明?如果这行得通,我希望能够声明子类的类型受限于它们的“三角形”,这样我就可以避免不必要的强制转换或辅助方法:

public class ChildModel<ChildView, ChildController> {

  public ChildModel () {
     this.controller <- calls ChildController type, not base type!
  }
}

有人有什么想法吗?

最佳答案

您似乎混淆了所有权和交互。所有权意味着一个人拥有另一个人,而互动则意味着他们如何相互交流。 MVC 主要定义三个参与者之间的交互,尽管您可以说 View 和 Controller 都拥有一个模型。

enter image description here

在您显示的代码中,一个类拥有一个属性,因此 Controller 类拥有一个 View ,而一个 View 拥有一个 Controller 。

var model = new Model();
var view  = new View<Controller<Model, View<Controller, Model>, ...

这不适用于泛型,因为交互变成了循环。这是鸡和蛋的问题:鸡来自鸡下的蛋。我们可以通过为 Controller 提供 View 的所有权以及模型的 Controller 和 View 所有权来解决大部分问题。

public class Model
{   
}

public interface IView<M>
{
    M Model { get; }
}

public class MyView : IView<Model>
{
    public MyView(Model model)
    {
        Model = model;
    }

    public Model Model
    {
        get;
    }
}

public interface IController<V, M>
{
    M Model { get; }
    V View { get; }
}

public class MyController : IController<MyView, Model>
{
    public MyController(MyView view, Model model)
    {
        View = view;
        Model = model;
    }

    public Model Model
    {
        get;
    }

    public MyView View
    {
        get;
    }
}

我们仍然使用泛型来做到这一点,并且您可以轻松访问到目前为止的大部分信息,而无需引入循环引用。

class Program
{
    public static void Main()
    {
        var model      = new Model();
        var view       = new MyView(model);
        var controller = new MyController(view, model);
    }
}

现在,如果您想确保 View 具有对 Controller 的引用,您可以通过属性来实现。

view.Controller = controller;

您可以无视我刚刚向您展示的所有内容 - 并走属性注入(inject)路线。这意味着您可以简单地执行此操作,而不是通过构造函数获取依赖项,这会对如何创建对象产生循环引用限制。

var model = new Model();
var view  = new View();
var controller = new Controller();

model.View = view;
model.Controller = controller;

view.Controller = controller;
view.Model = model;

controller.View = view;
controller.Model = model;

无论您使用什么方法,诀窍都是避免您当前代码中存在的循环依赖问题。大多数 MVC 框架都提供了丰富的数据绑定(bind),打破了类之间的直接耦合,但如果您没有,则必须编写一些东西或找到一些东西,或者在语言规则的范围内工作。

有很多方法可以解决这个问题。在我写这篇文章时,发布了另一个答案,因此您也应该看看它。

关于c# - 泛型类约束,其中 <T> 是约束泛型类的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39481881/

相关文章:

c# - 如何防止应用程序在任务管理器中被杀死?

C# SqlMethods 喜欢不工作

C# WInForms TextBox DataBinding 如果绑定(bind)属性更改则刷新 TetxtBox.Text

java - 我通过泛型声明了 String 的 ArrayList,但以某种方式用 Integer 填充了它。我破坏了java吗?

java - 在通用上下文中使用 getActualTypeArguments

c# - RestSharp 请求 momentapp 的 restful api

oop - 为什么协议(protocol)的关联类型在 Swift 中不使用泛型语法?

c# - MVC View 中的 Html 元素为空

asp.net-mvc - MVC项目PartialViewResult、ActionResult、ViewResult类之间有什么区别?

python - Django 的 html 模板替代品是什么?