實體類的動態生成(一)

2021-09-13 13:08:00 字數 2736 閱讀 3792

在應用開發中,通常都會涉及各種 pojo/poco 實體類(do, dto, bo, vo)的編寫,有時這些實體類還需要實現inotifypropertychanged介面以支援屬性變更通知,一般我們都會手寫這些**或者通過工具根據資料庫表定義抑或別的什麼模板、對映檔案之類的來生成它們。

但是,在業務實現中往往伴隨著諸如「如何簡單且高效的獲取某個實體例項有哪些屬性發生過變更?」、「變更後的值是什麼?」這樣的問題,而大致的解決方法有:

由實體容器來跟蹤例項的屬性變更;

改造實體類(譬如繼承特定實體基類,在基類中實現這些基礎構造)。

方法(1)需要配合一整套架構設計來提供支撐,也不是專為解決上述實體類的問題而設,並且實現和使用也都不夠簡單高效,故此略過不表。接下來我將通過幾篇文章來詳細闡述這些問題的來由以及解決方案,並給出完整的**實現以及效能比對測試。

萬里長城也是從第一塊磚頭開始磊起來的,就讓我們來搬第一塊磚吧:

public class user

set

}// c# 7.0 語法

public string name

// 懶漢寫法:僅限不需要操作成員欄位的場景

public string namespace

}

以上**特地用了三種編碼方式,它們被c#編譯器生成的il沒有模式上的不同,故而效能沒有任何區別,大家根據自己的口味採用某種即可,因為我們的原始碼由於歷史原因可能會有一些混寫,在此一併做個展示而已。

由於業務需要,我們希望實體類能支援屬性變更通知,即讓它支援inotifypropertychanged介面,這麼簡單的需求當然不在話下:

public class user : inotifypropertychanged

}public string name

}protected virtual void onpropertychanged(string propertyname)

}

一切看起來是那麼完美,但是,當我們寫了幾個這樣的實體類,尤其是有些實體類的屬性還不少時,體驗就有點糟糕了。自然我們會想到寫個實體基類來實現屬性變更通知的基礎構造,當然,在某些特定場景也可以通過工具來生成類似上面這樣的c#實體類檔案,但工具生成的方式有一定侷限性並且不易維護(譬如需要在生成的**基礎上進行特定改造),在此不再贅述。

在進行基礎類庫或api設計的時候,我有個建議:__從應用場景開始__。具體的作法是,先嘗試編寫使用這些api的應用**,待各種應用場景的使用**基本都完成後,api介面也就自然而然的確定了。譬如,在我們這個需求中我希望這麼去使用實體基類:

public class user : modelbase

public string name

}

有了這樣的實體基類後,增強了功能後**依然如第一塊磚的「基礎版本」一樣簡潔,真是高興啊!但這就夠了麼,能不能把具體實體類裡面的成員欄位也省了,交給基類來處理呢?嗯,有點意思,試著寫下應用場景**:

public class user : modelbase

}

看起來棒極了,**變得更簡潔了,真是天才啊!淡定,喪心病狂的 c# 設計者似乎看到了這種普遍的需求,於是在 c# 5 中增加了system.runtime.compilerservices.callermembernameattribute自定義標記,c# 編譯器將自動把呼叫者名字生成出來傳遞給加註了該標記的引數,因此這樣的**還可以繼續簡化:

public class user : modelbase

}

但是,屬性的 getter 裡面的那個型別強制轉換,怎麼看都像是一朵「烏雲」啊,能不能把它也去掉呢?嗯,利用c#的泛型型別推斷可以完美解決它,繼續強勢進化:

public class user : modelbase

}

哇喔,有點小崇拜自己了,這**漂亮的一批!至此,實體基類的api介面基本確定,已經迫不及待想要去實現它了。

using system;

using system.linq.expressions;

public class modelbase : inotifypropertychanged

實體基類的實現主要思路就是採用字典來記錄各屬性的變更值,有了這個基礎,要繼續增加諸如「獲取哪些屬性發生過變更」之類的需求自然就很容易了:

public class modelbase : inotifypropertychanged

具體的**就不在這裡貼出了,有興趣的可以參考:從功能角度上看,目前的設計還是不錯的。但是,某些方法的設計有嚴重效能缺陷的,主要有以下幾點:

每次讀寫屬性都會解析lambda 表示式的操作會產生巨大的效能損耗;

採用字典來儲存實體屬性值的設計機制,會導致值型別的屬性讀寫反覆被裝箱(boxing)、拆箱(unboxing);

字典的讀寫效率也遠低於直接操作成員欄位的語言原語方式。

本文可能會更新,請閱讀原文: 以避免因內容陳舊而導致的謬誤,同時亦有更好的閱讀體驗。

本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議

動態生成實體類

在開發中可能會遇到這幾種情況 1 ef或linq查詢出來的匿名物件在其它地方呼叫不方便,又懶的手動建實體類 2 通過datatable反射實體需要先建乙個類 頭痛 3 通過sql語句返回的實體也需要先建乙個類 頭痛 4 如果通過 生成器要寫模版,需要安裝或者不想生成一堆不用的類 為了解決上面的不便之...

EfCore DbFirst生成實體類

本文主要介紹dbfirst情況下,使用efcore命令生成實體類。一 安裝工具 dotnet ef dotnet ef 可以安裝為全域性或本地工具,全域性命令如下 安裝 dotnet tool install global dotnet ef 更新dotnet tool update global ...

json快速生成實體類

justcode 2016 11 04 16 19 1.利用這個工具,不知是那位寫的,真的是簡單實用,對於一些複雜的json有這樣的工具真的是如魚得水一樣.public list 城市 城市 public class 城市 public string 省 public list 市 市 public...