顧客に導入しているc#で構築したシステムが遅いとの指摘を受け、リフレクションがボトルネックなのかと思い、高速化に関してネットで調べました。
色々調べると、FastMemberを利用すると、高速化できるとのことだったので、
導入し、速度を検証してみました。
1.FastMemberの導入
nugetで、FastMemberの最新版をダウンロードします。
1 |
nuget.exe install FastMember -Version 1.5.0} |
2.リフレクションの変更
リフレクションは主に、DBからのデータを画面系のオブジェクトに変換する処理で
使用しています。DBのレコードは、3万件以上あり、さらに全プロパティのセッター/ゲッターににリフレクションを使っているので、非常に多くの処理にリフレクションを使用しています。
リフレクションはDotnet.Commons.ReflectionのObjectUtilクラスを利用しています。
以下は変更後のソースで、リフレクションをFastMemberのTypeAccessorクラスに変更しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
namespace Utils { public class ObjectUtil { private static Dictionary<string, PropertyInfo[]> PropertiesDic = new Dictionary<string,PropertyInfo[]>(); private static Dictionary<string, PropertyInfo> PropertyDic = new Dictionary<string, PropertyInfo>(); private static Dictionary<string, TypeAccessor> AccessorDic = new Dictionary<string, TypeAccessor>(); public static void AddTypeProperties(object srcObject) { var srcType = srcObject.GetType(); if (!PropertiesDic.ContainsKey(srcType.Name)) { PropertiesDic.Add(srcType.Name, srcType.GetProperties()); AccessorDic.Add(srcType.Name, TypeAccessor.Create(srcType, true)); var srcProperties = PropertiesDic[srcType.Name]; foreach (var srcProperty in srcProperties) { PropertyDic.Add(string.Format("{0}#{1}", srcType.Name, srcProperty.Name), srcProperty); } } } public static PropertyInfo GetTypePropertyInfo(object srcObject, string propertyName) { var srcType = srcObject.GetType(); PropertyInfo propInfoDestObj = null; var destKey = string.Format("{0}#{1}", srcType.Name, propertyName); if (PropertyDic.ContainsKey(destKey)) { propInfoDestObj = PropertyDic[destKey]; } return propInfoDestObj; } public static object CopyProperties(object srcObject, object destObject) { if (srcObject == null) { return destObject; } var srcType = srcObject.GetType(); var destType = destObject.GetType(); AddTypeProperties(srcObject); AddTypeProperties(destObject); var srcProperties = PropertiesDic[srcType.Name]; foreach (PropertyInfo propInfoFromObj in srcProperties) { var propInfoDestObj = GetTypePropertyInfo(destObject, propInfoFromObj.Name); if (propInfoDestObj == null || !propInfoDestObj.CanWrite) { continue; } TypeAccessor getAccessor = AccessorDic[srcType.Name]; TypeAccessor setAccessor = AccessorDic[destType.Name]; object srcValue = getAccessor[srcObject, propInfoFromObj.Name]; object destValue = Converter.Convert(srcValue, propInfoDestObj.PropertyType); setAccessor[destObject, propInfoDestObj.Name] = destValue; } return destObject; } } } |
3.経過時間の比較
Dotnet.Commons.ReflectionのObjectUtilクラスとFastMemberのTypeAccessorクラスとで、経過時間の比較してみました。約2倍くらい速くなっています。
リフレクションクラス | 呼び出し回数 | 処理時間 |
ObjectUtil | 45,332回 | 00:00:07.9593688 |
31,818回 | 00:00:06.4467155 | |
TypeAccessor | 45,332回 | 00:00:04.7315769 |
31,818回 | 00:00:03.3735334 |