麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

C#的泛型的類型參數可以有帶參數的構造函數的約束方式嗎?

2019-11-17 03:13:40
字體:
來源:轉載
供稿:網友

C#的泛型的類型參數可以有帶參數的構造函數的約束方式嗎?

Review后看到標題讓我十分羞愧自己語文功底太差,估計...請見諒......我還特地把這句寫回開頭了......

問題

前天遇到的一個問題,所以在MSDN發了個問,剛也豐富了下問題,關于泛型的。

最近用EF嘗試DDD常常有些奇怪的想法,比如“EF的Model First能否添加泛型支持”。這次是“泛型的類型能否有帶參數的約束方式”。

具體想法很簡單,在我使用泛型的時候,我發現我需要實例化一個類型參數:

1 class MyClass<T>2 {3     public MyClass1()4     {5         this.MyObject = new T();6     }7 8     T MyObject { get; set; }9 }

當然,上面會報錯

錯誤內容是T沒有一個new約束(new constraint),查閱下MSDN,得到了泛型的類型參數的new約束的內容。

所以接下來正確的代碼就是:

 1 class MyClass<T> 2     where T : new() 3 { 4     public MyClass1() 5     { 6         this.MyObject = new T(); 7     } 8  9     T MyObject { get; set; }10 }

然后,后來我發現,我需要根據參數來創建新的對象,而且該方法在泛型的構造函數中實現最合適,所以我希望有這樣的代碼:

 1 class MyClass1<T> 2     where T : new(string) 3 { 4     public MyClass(string request) 5     { 6         this.MyObject = new T(request); 7     } 8  9     T MyObject { get; set; }10 }

可惜這下就錯大了,然后查閱泛型的約束方式列表,發現根本沒有帶參數的構造函數這種約束

所以就發生了我上面在MSDN上問的那個問題,尋求一個“優雅的解決方案”。

一般解決方案就像問題中的回答那樣有兩種,也是我試過但是很不爽的兩種,我們依次看看。

補充:

  • 由James.Ying提醒,還有從構造函數傳入
  • 由@Choo提醒,用Activator.CreateInstance

工廠模式

首先是Factory Pattern,就是建一個工廠類,先看看代碼,這是其中一種寫法,請不要糾結在Factory Pattern上:

 1 class MyClass<T, TFactory> 2     where TFactory : IFactory<T>, new() 3 { 4     public MyClass(string request) 5     { 6         var factory = new TFactory(); 7  8         this.MyObject = factory.New(request); 9     }10 11     T MyObject { get; set; }12 }13 14 interface IFactory<T>15 {16     T New(string request);17 }

實現中你會發現,這樣需要為每個派生類或者實例類別創建并維護一個Factory類,那樣泛型本身就沒那么大意義了,本來就是為了減少類型重用邏輯而采用泛型的

抽象基類的靜態抽象方法

如果不想維護多一個類,那么就在目標類本身下手,所以我們可以為目標類創建一個基類:

 1 class MyClass<T> 2     where T : TBase, new() 3 { 4     public MyClass(string request) 5     { 6         this.MyObject = T.New(request); 7     } 8  9     T MyObject { get; set; }10 }11 12 abstract class TBase13 {14     public abstract static TBase New(string request);15 }

為了防止誤人子弟,首先要說在前頭的是,這樣寫是會編譯錯誤的!

約束上是沒錯的,但是它報的錯誤是類似于“T是個類型參數,不能這么用!”('T' is a 'type parameter', which is not valid in the given context)。

從構造函數傳入

還有一種基礎的做法反而忘記了,由James.Ying提醒想起來,就是從泛型類的構造函數傳入。

class MyClass<T>    where T : TBase, new(){    public MyClass(T myObject)    {        this.MyObject = myObject;    }    T MyObject { get; set; }}

這種方式使得泛型類簡潔多了,把實例化的過程交給了調用者,有點依賴倒置了(其實凡是應該在泛型里實現的而交給了調用者或者繼承者都是這樣)。

優點是泛型簡單了,缺點就是你無法保證實例化使用的構造函數是T(string)。另外,它可能會降低代碼的重用性。假設實例化是有條件地,而且所有派生類的邏輯是統一的,那么還是在泛型基類中實現比較好。

簡單情況下這是對泛型來說最優雅的方式了。

Activator.CreateInstance

該方法可以在http://msdn.microsoft.com/en-us/library/system.activator.createinstance(v=vs.110).aspx見到,說明就比較明確了:

用最匹配的構造函數創建一個類型的實例(Creates an instance of the specified type using the constructor that best matches the specified parameters)。

寫法也很爽:

class MyClass<T>{    public MyClass(string request)    {        this.MyObject = (T)Activator.CreateInstance(typeof(T), request);    }    T MyObject { get; set; }}

這種方法做得到,也很簡短,也不用多做接口和基類。

缺點就是沒有約束,沒辦法保證T能有帶指定數量和類型參數的構造函數,或者是否有構造函數。

如果T不符合設計需求的話會報相應的異常。

原來泛型的類型參數是這么設計的

至此,便可以知道,C#的泛型里,類型參數是一種“非類”的存在,類型參數的約束(Constraints on Type Parameters)僅僅是用來描述具體的類在實例化或者繼承時所需要達到的條件。而在泛型內部,類型參數僅僅是一種“特別的存在”,它用來描述類,但卻無法用作類。

那么,類型參數可以有......參考本文題目......

首先,其實這個問題本身就是泛型的類型參數能否有帶參數的實例化方式,比如T myObject = new T("Hello World!“)。

然后,由于類型參數是用“約束”的方式來進行實例類的特點的描述的,所以,問題才變成了泛型的類型參數能否有帶參數的構造函數的約束方式,比如where T : new(string)。

要做假設的話,起始就是個證偽的問題,要證明它存在是否會造成什么原則問題。

首先能對比的就是泛型的類型參數已經有了不帶參數的構造函數的約束方式了,那么泛型的類型參數就算有帶了參數的構造函數的約束方式又如何?至少,泛型的類型參數已經有了不帶參數的構造函數的約束方式證明了泛型的類型參數有構造函數的約束方式并不會造成什么問題而且技術上是可以實現的。(......)

在我們實例化一個新對象的時候通常會用兩種初始化方式:

  • 利用構造函數傳參
  • 實例化后賦值

大部分情況下兩種方式產生的結果是差不多的,這種大部分情況是指一般所涉及到的屬性或參數都是公開的(public),本來就是開放讀寫的,所以內部寫和外部寫都差不多。

但遇到一些情況,比如一些業務約束,需要對參數進行處理或者利用參數進行操作,最終操作結果是私密的(PRivate),那么就會偏向于選用構造函數傳參。或者會使用一個特殊的方法,由該方法在類實例化之后再把需要的數據帶進來進行操作,這么做些許有失“一氣呵成”的爽快。

利用構造函數傳參并不是什么容易替代的方式,因為它在絕大部分屬于它的場景里都是最優的解決方案。有時候,初始化一個對象到使用,一氣呵成是最好的,因為這個事務本身就有很強的原子性。一個對象的兩種初始化方式造成了雙入口的麻煩,作為該類的使用者,有時候你會模糊,兩種方式所產生的結果你無法準確地把握;對于開發者,兩種實現方式供的出現在規范上也要求要么二選一,要么保證兩者一致。當類變得相對復雜的時候,事情就沒那么簡單了。

所以,我們確實會需要泛型的類型參數有帶了參數的構造函數的約束方式的一些場景。它雖然不是必要的,但是絕對是一種需要,就像get/set訪問器那樣。

補充地說,其實更大的命題是類型參數是否可以當作類使用

假設它可以由帶參數的構造函數約束了,那么可不可以直接如約束那樣當作類來使用呢?比如調用靜態方法?在泛型中創建繼承于該類型參數的類?

如此種種算來發現每一種都有可能是特例,而不是一個簡單的實現即可解決的。

比如調用靜態方法來說,T.Hello()所涉及的就是執行的時候T能明確是哪個類;而在泛型類中創建繼承于該類型參數的類就會變得復雜。

單單想想調用那個類的方法:MyClass<T>.MySubClass,這里的語法就有點“不一般”了,未必是一個“僅僅是泛型本身的問題”。

逼格高一點地說,越來越多的功能對C#或者任何一門語言來說是一條正確的道路嗎?

關于題目

如果你有不滿,可以提供合適的標題,禁止以任何方式攻擊作者!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 一级黄片毛片免费看 | 国产羞羞网站 | 欧美18—19sex性hd按摩 | 成人毛片视频免费 | 精品国产一区二区三区四区阿崩 | 欧美亚洲一区二区三区四区 | 国产精品九九久久一区hh | 国产精品久久久久久久久久久久久久久 | 色天使中文字幕 | 久久精品中文字幕一区二区三区 | 72pao成人国产永久免费视频 | 欧美性受ⅹ╳╳╳黑人a性爽 | 欧美成人精品一区二区 | 久久久www成人免费精品 | 中文字幕一区久久 | 一区二区三区视频在线观看 | 欧美www | 精品中文字幕久久久久四十五十骆 | japanese massage tube| 网站激情 | 91麻豆精品国产91久久久更新资源速度超快 | 日韩视频中文 | 国产精品99久久久久久宅女 | 欧美成人精品不卡视频在线观看 | 香蕉视频99| 暴力肉体进入hdxxxx0 | 日本网站在线播放 | 国产在线1区 | 国产精品亚洲欧美 | 国产精品一区在线观看 | 国产精选电影免费在线观看 | 综合97 | 亚洲国产一区二区三区 | 国产成人精品一区二区视频免费 | 欧美日韩免费一区 | 日日操夜夜透 | 91一区二区在线观看 | 久久美女色视频 | 国产一区二区国产 | 日本网站一区 | 国产1区在线|