簡體   English   中英

通用類約束在哪里 <T> 是一種約束泛型類的類型

[英]Generic class constraint where <T> is a type constraining the generic class

也許不是最准確的標題,但它有點難以描述; 也許你們可以幫幫我嗎? 我正在使用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!
  }
}

有人有想法么?

看起來您將所有權與交互混淆。 所有權意味着一方擁有另一方,而交互意味着它們彼此之間的溝通方式。 MVC主要定義三個參與者之間的交互,但您可以說視圖和控制器都擁有一個模型。

在此輸入圖像描述

在如圖所示的代碼中,類擁有一個屬性,因此控制器類擁有一個視圖,一個視圖擁有一個控制器。

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.您應該使用Controller作為MVC模式的主要部分。 控制器應該從模式獲取信息,處理它然后調用視圖。

這是Controller的基類

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;

我想這就是你想要的:

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;
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM