Is it possible to speed this method up?
asp.net-3.5, c#, reflection
Solution
For your value class you can create direct setter and getter lambda. The performance is nearly as fast as directly accessing the properies.
Get Setter from PropertyInfo
var propertyInfo = typeof(MyType).GetProperty("MyPropertValue");
var propertySetter = FastInvoke.BuildUntypedSetter<T>(propertyInfo));
var fieldInfo = typeof(MyType).GetField("MyFieldValue");
var fieldSetter = FastInvoke.BuildUntypedSetter<T>(fieldInfo));
Usage in a loop
var myTarget = new MyType();
setter(myTarget, aNewValue)
Helper to retrieving fast Setter an Getter
public static class FastInvoke {
public static Func<T, object> BuildUntypedGetter<T>(MemberInfo memberInfo)
{
var targetType = memberInfo.DeclaringType;
var exInstance = Expression.Parameter(targetType, "t");
var exMemberAccess = Expression.MakeMemberAccess(exInstance, memberInfo); // t.PropertyName
var exConvertToObject = Expression.Convert(exMemberAccess, typeof(object)); // Convert(t.PropertyName, typeof(object))
var lambda = Expression.Lambda<Func<T, object>>(exConvertToObject, exInstance);
var action = lambda.Compile();
return action;
}
public static Action<T, object> BuildUntypedSetter<T>(MemberInfo memberInfo)
{
var targetType = memberInfo.DeclaringType;
var exInstance = Expression.Parameter(targetType, "t");
var exMemberAccess = Expression.MakeMemberAccess(exInstance, memberInfo);
// t.PropertValue(Convert(p))
var exValue = Expression.Parameter(typeof(object), "p");
var exConvertedValue = Expression.Convert(exValue, GetUnderlyingType(memberInfo));
var exBody = Expression.Assign(exMemberAccess, exConvertedValue);
var lambda = Expression.Lambda<Action<T, object>>(exBody, exInstance, exValue);
var action = lambda.Compile();
return action;
}
private static Type GetUnderlyingType(this MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
case MemberTypes.Field:
return ((FieldInfo)member).FieldType;
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
case MemberTypes.Property:
return ((PropertyInfo)member).PropertyType;
default:
throw new ArgumentException
(
"Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo"
);
}
}
}
============= Performance Analysis Added ===================
5 Mio Objects, 20 Properties
- 3.4s direct Property access
- 130.0s via PropertyInfo.SetValue
- 4.0s via TypedSetter (code shown in article)
- 9.8s via UnTypedSetter (code above)
The trick is to generate the property-setter and -getter once for each class an reuse them.
// Create an fill objects fast from DataReader
// http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
static List<T> CreateObjectFromReader<T>(IDataReader reader)
where T : new()
{
// Prepare
List<string> fieldNames = GetFieldNames(reader);
List<Action<T, object>> setterList = new List<Action<T, object>>();
// Create Property-Setter and store it in an array
foreach (var field in fieldNames)
{
var propertyInfo = typeof(T).GetProperty(field);
setterList.Add(FastInvoke.BuildUntypedSetter<T>(propertyInfo));
}
Action<T, object>[] setterArray = setterList.ToArray();
// generate and fill objects
while (reader.Read())
{
T xclass = new T();
int fieldNumber = 0;
for (int i = 0; i< setterArray.Length; i++)
{
// call setter
setterArray[i](xclass, reader.GetValue(i));
fieldNumber++;
}
result.Add(xclass);
}
}
My original article (german text and older code) was https://web.archive.org/web/20141020092917/http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
Problem
I have a method that uses loops through `7,753+` objects and Gets the value of each property for each object. Each object has `14` properties. ``` private void InitializeData(IList objects, PropertyInfo[] props, List<DPV> dataPs, List<Dictionary<string, object>> tod) { foreach (var item in objects) { var kvp = new Dictionary<string, object>(); foreach (var p in props) { var dataPs = dataPs.FirstOrDefault(x => x.Name == p.Name); object returnData; if (dataPoint != null) { int maxLength = (dataP.MaxLength == null) ? 0 : (int) dataP.MaxLength; returnData = p.GetValue(item, null); if (!string.IsNullOrEmpty(dataP.FormatString) && !string.IsNullOrEmpty(returnData.ToString())) { returnData = FormatDataForDisplay(returnData, dataP, maxLength, "", 8); } } else { returnData = p.GetValue(item, null); } kvp.Add(p.Name, returnData); } tod.Add(kvp); } } ``` I believe `GetValue` is what takes the majority of the time in this method, The method took around `900ms` to run, but `GetValue` which is called `800,000+` times takes around `750ms (total, not per-call)`. ``` public List<Dictionary<string, object>> GetColumnOptions<T>(List<T> list) { var tod= new List<Dictionary<string, object>>(); var objects = (IList)list[0]; Type objType = objects[0].GetType(); var props = objType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); var dPs= GetDPs(); //Initialize aaData //I don't believe this is correct InitializeData2<T>(new List<T> { (T) objects}, props, dPs, tod); return tod; } ```