Github 開源:高效好用的對象間屬性拷貝工具:升訊威 Mapper
對象屬性值映射/拷貝工具。不需要創建映射規則,不要求對象類型一致,適用於簡單直接的拷貝操作,可以全屬性拷貝,指定屬性拷貝,排除指定的屬性。拷貝包含 10 個屬性的對象 10 萬次,耗時 4.x 秒(普通開發機)。
+ 拷貝行為只針對 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。


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 來中國了!