通用类约束,其中<t>是约束泛型类的类型

时间:2016-09-14 03:03:45

标签: c# generics model-view-controller unity3d

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

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

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

这没关系,但每当我打算拉出ChildModel的控制器时,我都需要转换到相应的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; 
  }
}

正如您所看到的,这很快就会在基类中变得混乱。我不知道为什么符号(参考上面的例子)试图定义约束的模型。将“模型”放入问号似乎也没有编译,因为我遇到了一个地狱般的拳击转换问题。

有没有办法完成我所追求的目标,或者我只是想在这里过于聪明?如果这可行,我希望能够声明类型约束为“三角形”的子类,因此我可以避免不必要的强制转换或辅助方法:

public class ChildModel<ChildView, ChildController> {

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

有人有什么想法吗?

3 个答案:

答案 0 :(得分:1)

看起来您将所有权与互动混淆了。所有权意味着一方拥有另一方,而交互意味着它们彼此之间的沟通方式。 MVC主要定义三个参与者之间的交互,但你可以说视图和控制器都拥有一个模型。

enter image description here

在如图所示的代码中,类拥有属性,因此控制器类拥有视图,视图拥有控制器。

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

这不会以您希望的方式使用泛型,因为交互变为循环。这是鸡和蛋的问题:鸡来自鸡蛋,鸡蛋。我们可以通过赋予控制器对视图的所有权以及模型的控制器和视图所有权来解决大部分问题。

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 = controller;

你可以忽视我刚给你看的一切 - 然后去物业注射路线。这意味着不是通过构造函数接受依赖项,而是创建对象如何创建的循环引用限制,您可以简单地执行此操作。

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框架提供了丰富的数据绑定,这打破了类之间的直接耦合,但如果你没有这样,你必须要么写东西或者找东西,要么在语言规则的限制范围内工作。

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

答案 1 :(得分:0)

这是我的建议。 1.您应该使用Controller作为MVC模式的主要部分。控制器应该从模式获取信息,处理它然后调用视图。

这是控制器

的基类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Inheritance.Classes
{
    public class Controller<T, U> where T : Model, new() where U : View, new()
    {
        protected T _model;
        protected U _view;

        public Controller()
        {
            this._model = new T();
            this._view = new U();
        }

        public Controller(T model, U view)
        {
            this._model = model;
            this._view = view;
        }

        public string ParentFunction()
        {
            return "I'm the parent";
        }
    }
}

注意,我还有一个Model和View基类。由于它们目前是空的,我不会向您显示代码

然后,我可以定义我的子类。例如,我将创建一个PageController,PageModel和PageView。他们都将从他们的BaseClass继承。

注意:PageModel和PageView再次为空。它们仅用于继承

<强> PageController.cs

using Inheritance.Page;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Inheritance.Classes
{
    public class PageController : Controller<PageModel, PageView>
    {
        public PageController():base()
        {

        }

        public PageModel Model
        {
            get
            {
                return base._model;
            }
        }
    }
}

如您所见,您将仅在PageController内指定Model类和View类。

要使用您的课程,您可以执行以下操作:

        PageController controller = new PageController();

        //We can access the parent function
        Console.WriteLine(controller.ParentFunction());

        //Function defined into the controller.
        PageModel model =  controller.Model;

答案 2 :(得分:0)

我认为这就是你想要的:

public class GameModel : Model
{
    public int ID { get; set; }
}

public class GameView : View<GameModel, GameView>
{
    public float FOV { get; set; }
}

public class GameController : GameView.BaseControler
{
    // Set ID
    public GameController()
    {
        Model.ID=100;
        View.FOV=45f;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var gm = new GameModel();
        var view = new GameView();
        var ctrl = new GameController();

        view.Connect(gm, ctrl);

        Debug.WriteLine(view.Model.ID);
    }
}
public class Model
{

}

public class View<TModel,TView> where TModel : Model where TView : View<TModel, TView>
{
    public TModel Model { get; private set; }
    public BaseControler Controler { get; private set; }

    public void Connect(TModel model, BaseControler controler)
    {
        this.Model=model;
        this.Controler=controler;
        this.Controler.Connect(model, this as TView);
    }
    public class BaseControler
    {
        public TView View { get; private set; }
        public TModel Model { get; private set; }

        public void Connect(TModel model, TView view)
        {
            this.Model=model;
            this.View=view;
        }
    }
}