泛型

ORM實(shí)現(xiàn)有反射、泛型、代碼生成等幾種常見(jiàn)方式,或者單用,或者混合。

c#的泛型非常強(qiáng)大,應(yīng)用于ORM時(shí),可能有些特性顯得更重要。

一開(kāi)始實(shí)現(xiàn)coat時(shí),我嘗試寫(xiě)一下代碼做為ORM基類(lèi)

namespace Coat
{
    public class ORMBase<T> where T : class
    {
        ...
        public bool Update()
        {
            using (var conn = OpenConnection())
            {
                //Beblow compile error, because conn.Update<T> expect parameter to be T
                //i.e. the sub-class, but "this" is parent class.
                return conn.Update<T>(this);
            }
        }
    }
}

// 子類(lèi)生成的代碼類(lèi)似:
    public class User: ORMBase<User> {
    ...
    }

意圖是在基類(lèi)中實(shí)現(xiàn)ActiveRecord對(duì)象增刪改查等通用方法,相比起在具體子類(lèi)中使用代碼生成實(shí)現(xiàn)相應(yīng)的代碼會(huì)更簡(jiǎn)潔些。并且,編輯一個(gè)實(shí)際類(lèi)型,總比編輯模板方便。

做為一個(gè)玩了兩年沒(méi)有泛型的語(yǔ)言(GO)的人,我會(huì)覺(jué)得 c# class User: ORMBase<User> { 這樣的類(lèi)型聲明很強(qiáng)大。

User類(lèi)型繼承于ORMBase<T>,而類(lèi)型ORMBase<T>正是使用User類(lèi)型做為范型參數(shù)。這沒(méi)有循環(huán)依賴(lài)?

這樣ORMBase中,便可以利用泛型T做各種編程。

上面代碼是卡在了conn.Update<T>(this);這句調(diào)用。

因?yàn)閐apper的Update方法簽名類(lèi)似Update<T>(T entityToUpdate),我在ORMBase<T>中寫(xiě)的this是父類(lèi),也就是ORMBase<T>;而傳進(jìn)去給Update的類(lèi)型參數(shù)T,則是子類(lèi),比方說(shuō)User。

編譯器直接就報(bào)錯(cuò)了。

ORMBase<T>跟T是兩個(gè)不同的類(lèi)型,無(wú)法直接轉(zhuǎn)換,寫(xiě)conn.Update<T>((T)this);編譯器也是報(bào)錯(cuò)。

有同事建議修改ORMBase的Update簽名,變成public bool Update(T obj),然后把傳obj而不是this給dapper。

這樣雖然可以解決編譯問(wèn)題,但會(huì)讓?xiě)?yīng)用調(diào)用時(shí)變麻煩;還不如直接把Update方法搬去子類(lèi)里面生成出來(lái),但還是不漂亮。

研究了一番泛型約束,結(jié)果找到更漂亮的方式。

ORMBase<T>跟T無(wú)法相互轉(zhuǎn)換是因?yàn)榫幾g器不知道他們之間的繼承關(guān)系,把他們的繼承關(guān)系寫(xiě)到范型約束中便可以轉(zhuǎn)換了。

public class RecordBase<T> where T : RecordBase<T>

這樣聲明約束T必須是RecordBase<T>的子類(lèi);Update方法改為:

return conn.Update<T>((T)this);

便可以順利編譯了。

雖然可以編譯,但這里是把父類(lèi)轉(zhuǎn)換為子類(lèi),何以可以順利編譯,我其實(shí)還木有搞明白細(xì)節(jié)。

有朋友知道,還望告知。

謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • object 變量可指向任何類(lèi)的實(shí)例,這讓你能夠創(chuàng)建可對(duì)任何數(shù)據(jù)類(lèi)型進(jìn)程處理的類(lèi)。然而,這種方法存在幾個(gè)嚴(yán)重的問(wèn)題...
    CarlDonitz閱讀 1,018評(píng)論 0 5
  • 引言:泛型一直是困擾自己的一個(gè)難題,但是泛型有時(shí)一個(gè)面試時(shí)老生常談的問(wèn)題;今天作者就通過(guò)查閱相關(guān)資料簡(jiǎn)單談?wù)勛约簩?duì)...
    cp_insist閱讀 1,931評(píng)論 0 4
  • 一、為什么要使用泛型 1.類(lèi)型參數(shù)的好處 類(lèi)型安全:泛型的主要目標(biāo)是提高 Java 程序的類(lèi)型安全。通過(guò)知道使用泛...
    SeanMa閱讀 7,264評(píng)論 1 18
  • 我們知道,使用變量之前要定義,定義一個(gè)變量時(shí)必須要指明它的數(shù)據(jù)類(lèi)型,什么樣的數(shù)據(jù)類(lèi)型賦給什么樣的值。 假如我們現(xiàn)在...
    今晚打肉山閱讀 1,213評(píng)論 0 1
  • 第8章 泛型 通常情況的類(lèi)和函數(shù),我們只需要使用具體的類(lèi)型即可:要么是基本類(lèi)型,要么是自定義的類(lèi)。但是在集合類(lèi)的場(chǎng)...
    光劍書(shū)架上的書(shū)閱讀 2,198評(píng)論 6 10

友情鏈接更多精彩內(nèi)容