當前位置:
首頁 > 知識 > Github 開源:高效好用的對象間屬性拷貝工具:升訊威 Mapper

Github 開源:高效好用的對象間屬性拷貝工具:升訊威 Mapper

對象屬性值映射/拷貝工具。不需要創建映射規則,不要求對象類型一致,適用於簡單直接的拷貝操作,可以全屬性拷貝,指定屬性拷貝,排除指定的屬性。拷貝包含 10 個屬性的對象 10 萬次,耗時 4.x 秒(普通開發機)。

Github 開源:高效好用的對象間屬性拷貝工具:升訊威 Mapper

+ 拷貝行為只針對 sourceObject 和 targetObject 所共有的屬性

+ 在 sourceObject 和 targetObject 中的待拷貝的屬性值的類型處理:如果是值類型,直接拷貝,如果是引用類型,sourceObject 中的屬性的類型 必須 和 targetObject 中的屬性的類型一致,或是它的派生類

+ 如果要支持類型不一致的屬性自動進行類型轉換,你可以在 PropertyMappingDescription 這個類中實現轉換器功能

+ 拷貝行為 不會 改變 targetObject 中不需要被拷貝的屬性的值

+ 你可以組合使用幾個方法來從多個對象中拷貝指定的屬性值到一個 targetObject

和 AutoMapper 互補,與之相比最大優勢是短,平,快。不需要創建複雜的映射規則,並支持屬性排除操作。

具體實現:

這裡在具體實現上,其實並不複雜,只需對反射操作稍有了解即可,

我們通過 sourceObject 和 targetObject ,獲取它們的「類型(Type)」,然後使用 Type.GetProperties 方法,獲取這個對象類型所包含的屬性(Property)。

PropertyInfo propertyList = Type.GetProperties;
foreach (PropertyInfo property in propertyList)
{
PropertyMappingDescription propertyMappingDescription = new PropertyMappingDescription(property);

_propertyList.Add(propertyMappingDescription);
_propertyNames.Add(property.Name, propertyMappingDescription);
}

這裡有另外一個細節需要留意的是,我們要把同樣類型(Type)的相關信息,緩存起來,這樣下次再拷貝相同類型的對象時,就無需再去反射它的 Properties。

我們通過 TypeMappingDescription 對對象的類型信息進行緩存和包裝,提供我們所需要的基本操作:

public bool ContainsProperty(string name)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("TypeMappingDescription.ContainsProperty 必須指定屬性名。");

return _propertyNames.ContainsKey(name);
}

public object GetValue(object obj, string propertyName)
{
if (obj == null)
throw new ArgumentNullException("指定的對象為空。");

if (obj.GetType != this.Type)
throw new ArgumentException("指定的對象類型與緩存的對象類型不一致。");

if (_propertyNames.ContainsKey(propertyName) == false)
throw new ArgumentOutOfRangeException("指定的屬性名不存在。");

PropertyMappingDescription propertyMappingDescription = (PropertyMappingDescription)_propertyNames[propertyName];
if (propertyMappingDescription.CanRead == false)
throw new InvalidOperationException("屬性 " + propertyName + "不可讀。");

return propertyMappingDescription.GetValue(obj);
}

public void SetValue(object obj, string propertyName, object value)
{
if (obj == null)
throw new ArgumentNullException("指定的對象為空。");

if (obj.GetType != this.Type)
throw new ArgumentException("指定的對象類型與緩存的對象類型不一致。");

if (_propertyNames.ContainsKey(propertyName) == false)
throw new ArgumentOutOfRangeException("指定的屬性名不存在。");

PropertyMappingDescription propertyMappingDescription = (PropertyMappingDescription)_propertyNames[propertyName];
if (propertyMappingDescription.CanWrite == false)
throw new InvalidOperationException("屬性 " + propertyName + "只讀。");

Type propertyType = propertyMappingDescription.PropertyInfo.PropertyType;
if (propertyType.IsValueType == false && value != null)
{
Type valueType = value.GetType;
if(propertyType != valueType && valueType.IsSubclassOf(propertyType) == false)
{
throw new ArgumentException("目標對象的 " + propertyName + "與 value 的類型既不一致,也不是目標類型的派生類。");
}
}

propertyMappingDescription.SetValue(obj, value);
}

同時我們使用 PropertyMappingDescription 對 PropertyInfo 進行封裝。對 PropertyInfo 進行封裝,是為了方便我們後續針對屬性添加屬性值的轉換器,以便實現稍複雜一些的屬性拷貝操作。

最後我們來測試一下拷貝操作:

A a = new A
{
Name = "張三",
Age = 10,
Class = "一班",
CObject = new SubC
{
Message = "Hello"
},
P1 = "1",
P2 = "2",
P3 = "3",
P4 = "4",
P5 = "5",
P6 = "6"
};

B b = new B;

Stopwatch stopwatch = new Stopwatch;
stopwatch.Start;

for (int i = 0; i < 100000; i++) { //全部屬性拷貝 ShengMapper.SetValues(a, b); //拷貝指定的屬性 // ShengMapper.SetValuesWithProperties(a, b, new string[] { "Name", "Age", "P1" }); //排除指定的屬性 //ShengMapper.SetValuesWithoutProperties(a, b, new string[] { "Name", "Age", "P1" }); } stopwatch.Stop; Console.WriteLine("對包含 10 個屬性的對象的屬性值拷貝 10 萬次,耗時:" + stopwatch.Elapsed.ToString); Console.ReadLine;

我模擬了一幾個類,他們有不同類型的屬性,還包括引用類型的屬性我派生類。

對於包含 10 個屬性的類的 10 萬次屬性值拷貝,在開發機上大約用了 4.x 秒。

完整的代碼位於 Github。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

EF之通過不同條件查找去重複

TAG:科技優家 |

您可能感興趣

fish:Linux中比bash或zsh更好用的Shell
iPhoneXSMax使用一個月感受:比iPhoneX更好用
小米高管:iPhone XS Max既笨重又不好用?
思維導圖XMind、MindMaster和MindManager哪個好用?
Endnote不好用,不妨試試made in China的NoteExpress
Google News大改版 在iOS/Android/Web上更好用
miui、emui、flyme、coloros哪個系統好用?
Colour pop 真的那麼好用?難用?what!
和Adobe Project CloverVR一樣好用的AR/VR雲設計編輯器:Nibiru Creator
Angelababy的果凍粉撲好用么?
分享日記 I 你不知道的平價又大牌的歐美好用物……catrice,essence,misslyn.ARTDECO
德國彩妝平價又好用,Essence、Catrice終於到貨~ | 上新
HomePod將支持HomeKit應用 讓Siri變得更好用
最好用的自拼教材:牛津自然拼讀Oxford Phonics World
普天同慶:GitHub提供免費私有Repo,真的賊好用啊~
iPhone 8好用嗎?
TensorFlow、Keras、CNTK……到底哪種深度學習框架更好用?
只裝一個 App,讓你的 Windows 平板比 iPad 更好用 | 有用功
Zttp-一個基於 Guzzle Http 的更好用的 PHP HTTP Package
超火又好用的美妝品牌 Charlotte Tilbury 來中國了!