I have a system using dynamic run-time configuration of dynamically loaded types.
The system is loading Types based on XML and creating instances. It then reads "properties" from the XML file, setting these properties on the created instance. At this time, it works on simple properties directly on the instance, however, these types can have a hierarchy of settings unknown to the calling part.
I'm looking for a utils-library similar to Java BeanUtils [http://commons.apache.org/proper/commons-beanutils/]. I would want it to be able to do something like this (pseudo code):
Util.SetProperty(someInstance, "property1.property2, someValue);
Or perhaps with extensions:
someInstance.SetProperty("property1.property2, someValue);
And the reverse with Get of course.
Note that BeanUtils has it's own style of describing properties so it works for most types of properties, including lists.
Anything, or perhaps suggestions on different approach to the problem?
Here is a helper class which supports Lists, Dictionaries and nested Properties, you should extend it if you need to support multiple indexers (very rare cases).
public static class Helper
{
public static void SetProperty(object instance, string propery, object value)
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var properties = propery.Split('.');
var type = instance.GetType();
object[] index = null;
PropertyInfo property = null;
for (var i = 0; i < properties.Length; i++)
{
var indexValue = Regex.Match(properties[i], #"(?<=\[)(.*?)(?=\])").Value;
if (string.IsNullOrEmpty(indexValue))
{
property = type.GetProperty(properties[i], flags);
index = null;
}
else
{
property =
type.GetProperty(properties[i].Replace(string.Format("[{0}]", indexValue), string.Empty),
flags);
index = GetIndex(indexValue, property);
}
if (i < properties.Length - 1)
instance = property.GetValue(instance, index);
type = instance.GetType();
}
property.SetValue(instance, value, index);
}
public static object GetProperty(object instance, string propery)
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var properties = propery.Split('.');
var type = instance.GetType();
foreach (var p in properties)
{
var indexValue = Regex.Match(p, #"(?<=\[)(.*?)(?=\])").Value;
object[] index;
PropertyInfo property;
if (string.IsNullOrEmpty(indexValue))
{
property = type.GetProperty(p, flags);
index = null;
}
else
{
property =
type.GetProperty(p.Replace(string.Format("[{0}]", indexValue), string.Empty),
flags);
index = GetIndex(indexValue, property);
}
instance = property.GetValue(instance, index);
type = instance.GetType();
}
return instance;
}
private static object[] GetIndex(string indicesValue, PropertyInfo property)
{
var parameters = indicesValue.Split(',');
var parameterTypes = property.GetIndexParameters();
var index = new object[parameterTypes.Length];
for (var i = 0; i < parameterTypes.Length; i++)
index[i] = parameterTypes[i].ParameterType.IsEnum
? Enum.Parse(parameterTypes[i].ParameterType, parameters[i])
: Convert.ChangeType(parameters[i], parameterTypes[i].ParameterType);
return index;
}
}
and here is some Examples:
public enum Qwerty
{
Q,W,E,R,T,Y
}
class A
{
private int[,] _array=new int[10,10];
public B PropertyB { get; set; }
public int this[int i, int j]
{
get { return _array[i, j]; }
set { _array[i, j] = value; }
}
}
class B
{
public int Value { get; set; }
}
Nested Properties:
var a = new A { PropertyB = new B() };
Helper.SetProperty(a, "PropertyB.Value", 100);
var value = Helper.GetProperty(a, "PropertyB.Value");
Indexer (with multiple index):
var a = new A { PropertyB = new B() };
Helper.SetProperty(a, "Item[1,1]", 100);
var value = Helper.GetProperty(a, "Item[1,1]");
Lists:
var list = new List<int>() { 0, 1, 2, 3, 4 };
Helper.SetProperty(list, "Item[2]", 200);
var value = Helper.GetProperty(list, "Item[2]");
Nested Properties with Lists:
var list = new List<A>() { new A { PropertyB = new B() } };
Helper.SetProperty(list, "Item[0].PropertyB.Value", 75);
var value = Helper.GetProperty(list, "Item[0].PropertyB.Value");
Dictionaries:
var dic = new Dictionary<int, A> { { 100, new A { PropertyB = new B() } } };
var newA = new A { PropertyB = new B() { Value = 45 } };
Helper.SetProperty(dic, "Item[100]", newA);
var value = Helper.GetProperty(dic, "Item[100].PropertyB.Value");
Dictionaries with Enumeration as Key:
var dic = new Dictionary<Qwerty, A> { { Qwerty.Q, new A { PropertyB = new B() } } };
var newA = new A { PropertyB = new B() { Value = 45 } };
Helper.SetProperty(dic, "Item[Q]", newA);
var value = Helper.GetProperty(dic, "Item[Q].PropertyB.Value");
Enumeration as Value:
var list = new List<Qwerty>() { Qwerty.Q, Qwerty.W, Qwerty.E, Qwerty.R, Qwerty.T, Qwerty.Y };
Helper.SetProperty(list, "Item[2]", Qwerty.Q);
var value = Helper.GetProperty(list, "Item[2]");
Related
I have a Generic List of type List<InstanceDataLog> which has huge number of properties in it. I want to pass names of a few properties to a method and want to extract a refined List from within this list.
public void Export(string col) //a,b,c
{
string [] selectedcol = col.Split(',');
var grid = new GridView();
var data = TempData["InstanceDataList"];
List<InstanceDataLog> lst = new List<InstanceDataLog>();
List<EToolsViewer.APIModels.InstanceDataLog> lstrefined = new List<InstanceDataLog>();
lst= (List<EToolsViewer.APIModels.InstanceDataLog>)TempData["InstanceDataList"];
var r= lst.Select(e => new {e.a, e.b}).ToList();// I would like to replace these hardcoded properties with names of properties present in `selectedcol `
grid.DataSource =r;
grid.DataBind();
}
To clear things up further, suppose InstanceDataLog has 5 properties : a,b,c,d,e I would like pass a,b and be able to extract a new list with only properties a,b
EDIT:
$('#export').mousedown(function () {
window.location = '#Url.Action("Export", "TrendsData",new { col = "a,b,c" })';
});
You could use such method to get properties:
private object getProperty(EToolsViewer.APIModels.InstanceDataLog e, string propName)
{
var propInfo =typeof(EToolsViewer.APIModels.InstanceDataLog).GetProperty(propName);
return propInfo.GetValue(e);
}
and with another function you could get all properties you want:
private dynamic getProperties(string[] props, EToolsViewer.APIModels.InstanceDataLog e )
{
var ret = new ExpandoObject() as IDictionary<string, Object>;;
foreach (var p in props)
{
ret.Add(p, getProperty(e, p));
}
return ret;
}
The problem occurs if you try to assign DataSource with expando object. Solution is described hier:
Binding a GridView to a Dynamic or ExpandoObject object
We do need one more method:
public DataTable ToDataTable(IEnumerable<dynamic> items)
{
var data = items.ToArray();
if (data.Count() == 0) return null;
var dt = new DataTable();
foreach (var key in ((IDictionary<string, object>)data[0]).Keys)
{
dt.Columns.Add(key);
}
foreach (var d in data)
{
dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
}
return dt;
}
and use it:
var r = lst.Select(e => getProperties(selectedcol, e)).ToList();
grid.DataSource = ToDataTable(r);
The same thing, but ready to run for LinqPad:
void Main()
{
var samples = new[] { new Sample { A = "A", B = "B", C = "C" }, new Sample { A = "A1", B = "B2", C = "C1" } };
var r = samples.Select(e => getProperties(new[] {"A", "C", "B"}, e)).ToList();
r.Dump();
}
private object getProperty(Sample e, string propName)
{
var propInfo = typeof(Sample).GetProperty(propName);
return propInfo.GetValue(e);
}
private dynamic getProperties(string[] props, Sample e)
{
var ret = new ExpandoObject() as IDictionary<string, Object>; ;
foreach (var p in props)
{
ret.Add(p, getProperty(e, p));
}
return ret;
}
public class Sample
{
public string A { get; set;}
public string B { get; set;}
public string C { get; set;}
}
With output:
To keep compiler type/name checking suggest to pass a Func<InstanceDataLog, TResult> instead of array of names
public void Export<TResult>(Func<InstanceDataLog, TResult> selectProperties)
{
var grid = new GridView();
var data = TempData["InstanceDataList"];
var originalList = (List<InstanceDataLog>)TempData["InstanceDataList"];
var filteredList = originalList.Select(selectProperties).ToList();
grid.DataSource = filteredList;
grid.DataBind();
}
Then use it:
Export(data => new { Id = data.Id, Name = data.Name });
I get an exception when I try to set a nested member Property using FastMember. For example when having these classes
public class A
{
public B First { get; set; }
}
public class B
{
public string Second { get; set; }
}
and I want to set First.Second of an instance to "hello".
var b = new B{ Second = "some value here" };
var a = new A{ First = b };
var accessor = ObjectAccessor.Create(a);
accessor["First.Second"] = value; // this does not work and gives ArgumentOutOfRangeException
I can't split it up into ["First"]["Second"] because I don't know the depth at this point. Is there a magical access for nested properties or do I have to split the hierarchy myself?
I solved the problem recursively using an Extension Method this way:
public static class FastMemberExtensions
{
public static void AssignValueToProperty(this ObjectAccessor accessor, string propertyName, object value)
{
var index = propertyName.IndexOf('.');
if (index == -1)
{
accessor[propertyName] = value;
}
else
{
accessor = ObjectAccessor.Create(accessor[propertyName.Substring(0, index)]);
AssignValueToProperty(accessor, propertyName.Substring(index + 1), value);
}
}
}
... and this is started as follows:
ObjectAccessor.Create(a).AssignValueToProperty("First.Second", "hello")
You need to traverse the object graph using multiple ObjectAccessor instances.
public static void UseFastMember()
{
var b = new B { Second = "some value here" };
var a = new A { First = b };
var value = "hello";
var a_accessor = ObjectAccessor.Create(a);
var first = a_accessor["First"];
var b_accessor = ObjectAccessor.Create(first);
b_accessor["Second"] = value;
}
Hats off to #Beachwalker for the inspiration. But should you be using TypeAccessor as opposed to ObjectAccessor this is an extension method I've had much success with:
public static class TypeAccessorExtensions
{
public static void AssignValue<T>(this TypeAccessor accessor, T t, MemberSet members, string fieldName, object fieldValue)
{
var index = fieldName.IndexOf('.');
if (index == -1)
{
if (members.Any(m => string.Equals(m.Name, fieldName, StringComparison.OrdinalIgnoreCase)))
accessor[t, fieldName] = fieldValue;
}
else
{
string fieldNameNested = fieldName.Substring(0, index);
var member = members.FirstOrDefault(m => string.Equals(m.Name, fieldNameNested, StringComparison.OrdinalIgnoreCase));
if (member != null)
{
var nestedAccesor = TypeAccessor.Create(member.Type);
var tNested = accessor[t, fieldNameNested];
if (tNested == null)
{
tNested = Activator.CreateInstance(member.Type);
accessor[t, fieldNameNested] = tNested;
}
nestedAccesor.AssignValue(tNested, nestedAccesor.GetMembers(), fieldName.Substring(index + 1), fieldValue);
}
}
}
}
I have a class, that has several elements of normal types, like int, String, etc.
It also has several elements that are various lists of other classes, that could be empty or have 1 to many items.
I have a function that I call with a generic type of the parent class, and I want to analyze data that could be in the sub elements, without knowing the types.
I am getting the parent members with the following code:
var getProperty = System.Runtime.CompilerServices.
CallSite<Func<System.Runtime.CompilerServices.CallSite,
object, object>>
.Create(Microsoft.CSharp.RuntimeBinder.
Binder.GetMember(0, property.Name, thisObject.GetType(), new[]
{
Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null)
}));
var thisValue = getProperty.Target(getProperty, thisObject);
I get the value into the var thisValue. At this point if I determine the underlying type of thisValue is a type of list, how can I grab the type of the list contents?
Here is the actual function....I can't seem to get it formatted nicely.
public static bool ObjectIsLike<T>(this T thisObject, T compareObject, params object[] argumentsToExclude)
{
for (int counter = 0; counter < argumentsToExclude.Length - 1; counter++)
{
argumentsToExclude[counter] = argumentsToExclude[counter].ToString().ToUpper();
}
bool objectIsLike = true;
foreach (var property in thisObject.GetType().GetProperties())
{
string fieldName = property.Name;
if (!argumentsToExclude.Contains(fieldName.ToUpper()))
{
try
{
var getProperty = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, property.Name, thisObject.GetType(), new[] { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null) }));
var thisValue = getProperty.Target(getProperty, thisObject);
getProperty = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, property.Name, compareObject.GetType(), new[] { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null) }));
var compareValue = getProperty.Target(getProperty, compareObject);
if (!(compareValue == null && thisValue == null))
{
if (compareValue == null || thisValue == null)
objectIsLike = false;
else
if (compareValue.GetType().FullName.Contains("List"))
{
//Ignore Lists
}
else
if (!compareValue.Equals(thisValue))
{
objectIsLike = false;
}
}
}
catch
{
objectIsLike = false;
}
}
}
return objectIsLike;
}
would GetType() work for you?
class Program
{
static void Main(string[] args)
{
MyClass1 c1 = new MyClass1();
foreach (var s in c1.pp)
{
Console.WriteLine(s.GetType());
}
Console.Read();
}
}
public class MyClass1
{
public MyClass2 p;
public List<object> pp;
public MyClass1()
{
p = new MyClass2();
pp = new List<object>();
pp.Add(new MyClass2());
pp.Add(new MyClass3());
pp.Add(new MyClass4());
}
}
public class MyClass2
{
public List<object> ppp;
public MyClass2()
{
ppp = new List<object>();
ppp.Add(new MyClass3());
ppp.Add(new MyClass4());
}
}
public class MyClass3
{
public int v;
}
public class MyClass4
{
public int v;
}
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;
}
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
If the problem is really in PropertyInfo.GetValue method call you can use the approach with building property-getters cache (for example via compiled expressions).
Here is the sample that demostrates that this approach is up to 30-40% faster than original method on 8000 objects with 14 properties (with hot cache):
static void Main(string[] args) {
IList objects = new List<Obj>();
for(int i = 0; i < 8000; i++)
objects.Add(new Obj());
var properties = typeof(Obj).GetProperties();
var sw1 = System.Diagnostics.Stopwatch.StartNew();
InitializeData1(objects, properties, new List<Dictionary<string, object>>());
sw1.Stop();
Console.WriteLine("Reflection PropertyInfo.GetValue: " + sw1.ElapsedTicks.ToString());
// cold cache testing
var sw2_coldCache = System.Diagnostics.Stopwatch.StartNew();
InitializeData2<Obj>(objects, properties, new List<Dictionary<string, object>>(), new Dictionary<string, Func<Obj, object>>());
sw2_coldCache.Stop();
Console.WriteLine("Cached Getters (Cold cache): " + sw2_coldCache.ElapsedTicks.ToString());
// cache initialization
InitializeData2<Obj>(new List<Obj> { new Obj() }, properties, new List<Dictionary<string, object>>(), gettersCache);
// hot cache testing
var sw2_hotCache = System.Diagnostics.Stopwatch.StartNew();
InitializeData2<Obj>(objects, properties, new List<Dictionary<string, object>>(), gettersCache);
sw2_hotCache.Stop();
Console.WriteLine("Cached Getters (Hot cache): " + sw2_hotCache.ElapsedTicks.ToString());
var sw3 = System.Diagnostics.Stopwatch.StartNew();
InitializeData3(objects, properties, new List<Dictionary<string, object>>());
sw3.Stop();
Console.WriteLine("returnProps special method: " + sw3.ElapsedTicks.ToString());
var sw4 = System.Diagnostics.Stopwatch.StartNew();
InitializeData2_NonGeneric(objects, properties, new List<Dictionary<string, object>>());
sw4.Stop();
Console.WriteLine("Cached Getters (runtime types resolving): " + sw4.ElapsedTicks.ToString());
}
Here is the original implementation (reduced for test purposes):
static void InitializeData1(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod) {
foreach(var item in objects) {
var kvp = new Dictionary<string, object>();
foreach(var p in props) {
kvp.Add(p.Name, p.GetValue(item, null));
}
tod.Add(kvp);
}
}
Here is the optimized implementation:
static IDictionary<string, Func<Obj, object>> gettersCache = new Dictionary<string, Func<Obj, object>>();
static void InitializeData2<T>(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod, IDictionary<string, Func<T, object>> getters) {
Func<T, object> getter;
foreach(T item in objects) {
var kvp = new Dictionary<string, object>();
foreach(var p in props) {
if(!getters.TryGetValue(p.Name, out getter)) {
getter = GetValueGetter<T>(p);
getters.Add(p.Name, getter);
}
kvp.Add(p.Name, getter(item));
}
tod.Add(kvp);
}
}
static Func<T, object> GetValueGetter<T>(PropertyInfo propertyInfo) {
var instance = System.Linq.Expressions.Expression.Parameter(propertyInfo.DeclaringType, "i");
var property = System.Linq.Expressions.Expression.Property(instance, propertyInfo);
var convert = System.Linq.Expressions.Expression.TypeAs(property, typeof(object));
return (Func<T, object>)System.Linq.Expressions.Expression.Lambda(convert, instance).Compile();
}
Test class:
class Obj {
public int p00 { set; get; }
public string p01 { set; get; }
public float p02 { set; get; }
public double p03 { set; get; }
public char p04 { set; get; }
public byte p05 { set; get; }
public long p06 { set; get; }
public int p07 { set; get; }
public string p08 { set; get; }
public float p09 { set; get; }
public double p10 { set; get; }
public char p11 { set; get; }
public byte p12 { set; get; }
public long p13 { set; get; }
}
Update: Added solution from varocarbas into tests
static void InitializeData3(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod) {
foreach(Obj item in objects) {
var kvp = new Dictionary<string, object>();
foreach(var p in props) {
kvp.Add(p.Name, returnProps(p.Name, item));
}
tod.Add(kvp);
}
}
static object returnProps(string propName, Obj curObject) {
if(propName == "p00") {
return curObject.p00;
}
else if(propName == "p01") {
return curObject.p01;
}
else if(propName == "p02") {
return curObject.p02;
}
else if(propName == "p03") {
return curObject.p03;
}
else if(propName == "p04") {
return curObject.p04;
}
else if(propName == "p05") {
return curObject.p05;
}
else if(propName == "p06") {
return curObject.p06;
}
else if(propName == "p07") {
return curObject.p07;
}
else if(propName == "p08") {
return curObject.p08;
}
else if(propName == "p09") {
return curObject.p09;
}
else if(propName == "p10") {
return curObject.p10;
}
else if(propName == "p11") {
return curObject.p11;
}
else if(propName == "p12") {
return curObject.p12;
}
else if(propName == "p13") {
return curObject.p13;
}
return new object();
}
Console Results: (Release, x64) (Core i5 M560 #2.67 GHz, 8GB RAM, Win7x64)
Reflection PropertyInfo.GetValue: 161288
Cached Getters (Cold cache): 153808
Cached Getters (Hot cache): 110837
returnProps special method: 128905
Thus, the caching approach is the best.
UPDATE2
The methods demonstrated in sample are intended to be used when the type of objects elements is known at compile time (generic way):
InitializeData2<Obj>(...)
If you are using the objects list which type is unknown at compile-time, you can use the following approach to invoke the InitializeData2<> generic method at run-time:
InitializeData2_NonGeneric(objects, properties, new List<Dictionary<string, object>>());
//...
static void InitializeData2_NonGeneric(IList objects, PropertyInfo[] props, List<Dictionary<string, object>> tod) {
Type elementType = objects[0].GetType();
var genericMethodInfo = typeof(Program).GetMethod("InitializeData2", BindingFlags.Static | BindingFlags.NonPublic);
var genericMethod = genericMethodInfo.MakeGenericMethod(new Type[] { elementType });
var genericGetterType = typeof(Func<,>).MakeGenericType(elementType,typeof(object));
var genericCacheType = typeof(Dictionary<,>).MakeGenericType(typeof(string), genericGetterType);
var genericCacheConstructor = genericCacheType.GetConstructor(new Type[] { });
genericMethod.Invoke(null, new object[] { objects, props, tod, genericCacheConstructor.Invoke(new object[] { }) });
}
I did a simple test where I replaced the problematic .GetValue with a function performing a simplistic assignation ("if the name of the property is blabla, the value is Object.blabla"). The test consists just in a simple version of your function/variable/properties and a loop allowing to have full control over the number of iterations. The results have been certainly surprising: the new approach is 10 times faster! Bear in mind that in my original tests (50000 iterations) the times were 2276 (old) vs. 234 (new). This difference remains constant for different scenarios; for example for 8000 iterations, it delivers 358ms vs. 36ms. I have done these tests on a pretty powerful computer and on C# winforms; #Xaisoft can take the code below, perform a test under his specific conditions and tell the results.
The code:
private void Form1_Load(object sender, EventArgs e)
{
List<List> var = new List<List>();
List var1 = new List();
var1.var = 1;
var1.var2 = 1;
var1.var3 = 1;
var1.var4 = 1;
var1.var5 = 1;
List var2 = new List();
var2.var = 1;
var2.var2 = 1;
var2.var3 = 1;
var2.var4 = 1;
var2.var5 = 1;
List var3 = new List();
var3.var = 1;
var3.var2 = 1;
var3.var3 = 1;
var3.var4 = 1;
var3.var5 = 1;
List var4 = new List();
var4.var = 1;
var4.var2 = 1;
var4.var3 = 1;
var4.var4 = 1;
var4.var5 = 1;
var.Add(var1);
var.Add(var2);
var.Add(var3);
var.Add(var4);
InitializeData(var, typeof(List).GetProperties());
}
private static void InitializeData(List<List> objects, PropertyInfo[] props)
{
DateTime start = DateTime.Now;
int count = 0;
do
{
count = count + 1;
foreach (var item in objects)
{
foreach (var p in props)
{
object returnData = p.GetValue(item, null); //returnProps(p.Name, item);
}
}
} while (count < 50000);
TimeSpan timer = new TimeSpan();
timer = DateTime.Now.Subtract(start);
}
private class List
{
public int var { set; get; }
public int var2 { set; get; }
public int var3 { set; get; }
public int var4 { set; get; }
public int var5 { set; get; }
public int var6 { set; get; }
public int var7 { set; get; }
public int var8 { set; get; }
public int var9 { set; get; }
public int var10 { set; get; }
public int var11 { set; get; }
public int var12 { set; get; }
public int var13 { set; get; }
public int var14 { set; get; }
}
private static object returnProps(string propName, List curObject)
{
if (propName == "var")
{
return curObject.var;
}
else if (propName == "var2")
{
return curObject.var2;
}
else if (propName == "var3")
{
return curObject.var3;
}
else if (propName == "var4")
{
return curObject.var4;
}
else if (propName == "var5")
{
return curObject.var5;
}
else if (propName == "var6")
{
return curObject.var6;
}
else if (propName == "var7")
{
return curObject.var7;
}
else if (propName == "var8")
{
return curObject.var8;
}
else if (propName == "var9")
{
return curObject.var9;
}
else if (propName == "var10")
{
return curObject.var10;
}
else if (propName == "var11")
{
return curObject.var11;
}
else if (propName == "var12")
{
return curObject.var12;
}
else if (propName == "var13")
{
return curObject.var13;
}
else if (propName == "var14")
{
return curObject.var14;
}
return new object();
}
FINAL NOTE: I would like people to understand so impressive results more generically than just applied to .GetValue. Nowadays computers can deal with lots of things and you don't really need to maximise the performance of each single bit, this is true. On the other hand, if you have performance problems and you need to "save resources" in a more relevant way, you should focus your improvements on the idea "the simpler, the quicker". I have done myself performance improvements in codes using a relevant number of Lists and Dictionaries and the results are noticiable even after each single change (List into conventional Array). You don't need to be too alarmist on this front but, in case of being required, remember that the memory consumption/associated time requirements to a List with respect to an Array are higher (and both elements do basically the same). Same thing for multi-dimension arrays, long-sized arrays, etc.
------ MORE DETAILED PERFORMANCE ANALYSIS
Even though I have let my point very clear since the start (just an idea which has to be adapted to each situation), I do understand that my claim (10 times faster) do require a proper definition. I have been doing tests under different conditions and here come the results:
NOTE: the aforementioned results were output by a 32-bit executable; all the ones below come from a 64-bit one. I have observed an improvement on the .GetValue performance when moving from 32-bit to 64-bit. The updated 64-bit version of the results above are (ms):
GetValue Direct Assignation
50000 iterations -> 1197 157
80000 iterations -> 1922 253
100000 iterations -> 2354 310
Thus, the ratio changes from 10 times to 7.5 times.
I started increasing the number of properties (every time on 64-bit) and GetValue became better and better. Results:
28 Properties
GetValue Direct Assignation
50000 iterations -> 2386 552
80000 iterations -> 3857 872
Aver. ratio = 4.37
50 Properties
GetValue Direct Assignation
50000 iterations -> 4292 1707
80000 iterations -> 6772 2711
Aver. ratio = 2.475
I am not sure if the improvement of GetValue will continue and will reach a point where will be better than the simplistic approach but who cares? At this point, it is clear that the increasing number of properties plays against the simplistic approach, so it is time to try a different (again pretty simplistic) alternative: global array storing all the properties.
private static int[,] List0;
Being populated in parallel with the given property (i.e., when object.propX = any value the corresponding positions in the array are also populated) and referred by objects/properties positions (first object, third property, etc.). Logically, this has the limitation of the number of objects (growing the first dimension above 1000 does not sound recommendable), but you might rely on different arrays (one storing from the first object to the 1000th one, other from the 1001th to the 2000th, etc.); you can set a function taking as argument the object name and returning the corresponding array.
Modifications in the main loop:
int countObject = -1;
foreach (var item in objects)
{
countObject = countObject + 1;
int countProp = -1;
foreach (var p in props)
{
countProp = countProp + 1;
object returnData = List0[countObject, countProp];
}
}
By running this new approach in the case above, I get:
50 Properties
GetValue 2D Array
80000 iterations -> 6772 155
Aver. ratio = 45.146
One more:
70 Properties
GetValue 2D Array
80000 iterations -> 10444 213
Aver. ratio = 49.06
And I stopped my tests here. I guess that it is more than enough to prove my point.
Different approaches deliver different performances under different conditions and thus the best way to know the ideal configuration for a situation is actually testing it. Relying on an ultimate truth is rarely the best solution for a problem (although I might be wrong... still waiting for the reply from DmitryG to test his solution under different conditions). Thus, UNDER THE TESTED CONDITIONS, it seems to be the case that the original simplistic approach is acceptable for cases where the number of properties is relatively low (i.e., below 20); above this, the required hardcoding effort does not seem to be worthy and relying on a different alternative (like the 2D array I proposed) is better. In any case, GetValue delivers clearly a bad performance, which might be improved in many different ways.
I hope that I will not need to update this answer again :)
Continued from post above:
Your code builds a dictionary of property name and (formatted) value.
So we need just a List as input. From T we can derive all information.
public Dictionary<string, object> ExtractParameterNameAndValue<T>(List<T> colleciton)
where T : class
{
var result = new Dictionary<string, object>();
// out of the loop - generate getters
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var getterList = new List<Func<T,object>>();
foreach (var p in properties)
{
getterList.Add(MyStatic.BuildUntypedGetter<T>(p));
}
// Array of getters
var getters = getterList.ToArray(); // improving performance (?) - never use Dictionary
// Corresponding array of Names
var names = properties.Select(p => p.Name).ToArray();
// iterate all data
int counter = 0;
foreach (var item in colleciton)
{
for (int i = 0; i< getters.Length; i++)
{
var name = names[i]; // name from property
var value = getters[i](item); // value from getter-call
result.Add(counter + " " + name, value);
}
counter++;
}
return result; ;
}
The method BuildUntypedGetter() is like
// see http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
public static Func<T, object> BuildUntypedGetter<T>(PropertyInfo propertyInfo)
{
var targetType = propertyInfo.DeclaringType;
var methodInfo = propertyInfo.GetGetMethod();
var returnType = methodInfo.ReturnType;
var exTarget = Expression.Parameter(targetType, "t");
var exBody = Expression.Call(exTarget, methodInfo);
var exBody2 = Expression.Convert(exBody, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(exBody2, exTarget);
var action = lambda.Compile();
return action;
}
There is no need to specify the type in the call. It is detected by type inference.
var accountList = new List<Account>()
{
new Account { Name = "X1", Name2 ="X2"},
new Account { Name = "X3", Name2 ="X4"},
new Account { Name = "X5", Name2 ="X6"},
};
var result = ExtractParameterNameAndValue(accountList);
This is a learning exercise in expression trees.
I have this working code:
class Foo
{
public int A { get; set; }
public string B { get; set; }
}
class Bar
{
public int C { get; set;}
public string D { get; set; }
}
class FieldMap
{
public PropertyInfo From { get; set; }
public PropertyInfo To { get; set; }
}
class Program
{
static Action<TFrom, TTo> CreateMapper<TFrom, TTo>(IEnumerable<FieldMap> fields)
{
ParameterExpression fromParm = Expression.Parameter(typeof(TFrom), "from");
ParameterExpression toParm = Expression.Parameter(typeof(TTo), "to");
//var test = new Func<string, string>(x => x);
//var conversionExpression = Expression.Call(null, test.Method);
var assignments = from fm in fields
let fromProp = Expression.Property(fromParm, fm.From)
let toProp = Expression.Property(toParm, fm.To)
select Expression.Assign(toProp, fromProp);
var lambda = Expression.Lambda<Action<TFrom, TTo>>(
Expression.Block(assignments),
new ParameterExpression[] { fromParm, toParm });
return lambda.Compile();
}
static void Main(string[] args)
{
var pa = typeof(Foo).GetProperty("A");
var pb = typeof(Foo).GetProperty("B");
var pc = typeof(Bar).GetProperty("C");
var pd = typeof(Bar).GetProperty("D");
var mapper = CreateMapper<Foo, Bar>(new FieldMap[]
{
new FieldMap() { From = pa, To = pc },
new FieldMap() { From = pb, To = pd }
});
Foo f = new Foo();
Bar b = new Bar();
f.A = 20;
f.B = "jason";
b.C = 25;
b.D = "matt";
mapper(f, b); // copies properties from f into b
}
}
Works nicely. As noted it copies the corresponding properties from f to b. Now, supposing I wanted to add some conversion or formatting method that takes the "from property", does some magic, and then sets the "to property" equal to the result. Note the two commented out lines in the middle of CreateMapper.
How do I accomplish this? I got this far, but I'm sort of lost now.
Your code sample is almost there; you can use Expression.Call to do the transformation as you are clearly trying to do. Instead of assigning toProp to the fromProp MemberExpression, you can assign to a MethodCallExpression representing the value of the transformation.
The tricky part here is to figure out how to do the transformation, which I assume will vary for different properties.
You can replace the LINQ expression with:
var assignments = from fm in fields
let fromProp = Expression.Property(fromParm, fm.From)
let fromPropType = fm.From.PropertyType
let fromTransformed
= Expression.Call(GetTransform(fromPropType), fromProp)
let toProp = Expression.Property(toParm, fm.To)
select Expression.Assign(toProp, fromTransformed);
(Notice that the right-hand side of the assignment is now fromTransformed rather than fromProp.)
where GetTransform looks something like (I've assumed here that the nature of the transformation depends only on the type of the property):
private static MethodInfo GetTransform(Type type)
{
return typeof(Program).GetMethod(GetTransformName(type));
}
private static string GetTransformName(Type type)
{
if (type == typeof(int))
return "MapInt";
if (type == typeof(string))
return "MapString";
throw new ArgumentException("Unknown type");
}
Then the only thing left to do is filling in the transformations themselves; for example:
public static int MapInt(int x) { return x * 2; }
public static string MapString(string x) { return x + x; }
Then, your usage-test method would produce:
b.c == 40
b.d == "jasonjason"
I had a bit of a play with your code and I think I can give you a nice fluent-style field map builder. Given your classes Foo & Bar you could run this code:
var foo = new Foo() { A = 20, B = "jason", };
var bar = new Bar() { C = 25, D = "matt", };
var fm = new FieldMapBuilder<Foo, Bar>()
.AddMap(f => f.A, b => b.C)
.AddMap(f => f.B, b => b.D)
.AddMap(f => f.A, b => b.D, x => String.Format("!{0}!", x))
.Compile();
fm(foo, bar);
The result is that bar now looks as if it were declared like so:
var bar = new Bar() { C = 20, D = "!20!", };
The nice thing about this code is you don't need to do any reflection in the calling code, property types are inferred, and it neatly handles mapping properties of different types.
Here's the code that does it:
public class FieldMapBuilder<TFrom, TTo>
{
private Expression<Action<TFrom, TTo>>[] _fieldMaps = null;
public FieldMapBuilder()
{
_fieldMaps = new Expression<Action<TFrom, TTo>>[] { };
}
public FieldMapBuilder(Expression<Action<TFrom, TTo>>[] fieldMaps)
{
_fieldMaps = fieldMaps;
}
public FieldMapBuilder<TFrom, TTo> AddMap<P>(
Expression<Func<TFrom, P>> source,
Expression<Func<TTo, P>> destination)
{
return this.AddMap<P, P>(source, destination, x => x);
}
public FieldMapBuilder<TFrom, TTo> AddMap<PFrom, PTo>(
Expression<Func<TFrom, PFrom>> source,
Expression<Func<TTo, PTo>> destination,
Expression<Func<PFrom, PTo>> map)
{
var paramFrom = Expression.Parameter(typeof(TFrom), "from");
var paramTo = Expression.Parameter(typeof(TTo), "to");
var invokeExpressionFrom =
Expression.Invoke(map, Expression.Invoke(source, paramFrom));
var propertyExpressionTo =
Expression.Property(paramTo,
(destination.Body as MemberExpression).Member as PropertyInfo);
var assignmentExpression =
Expression.Assign(propertyExpressionTo, invokeExpressionFrom);
return new FieldMapBuilder<TFrom, TTo>(
_fieldMaps.Concat(new Expression<Action<TFrom, TTo>>[]
{
Expression.Lambda<Action<TFrom, TTo>>(
assignmentExpression,
paramFrom,
paramTo)
}).ToArray());
}
public Action<TFrom, TTo> Compile()
{
var paramFrom = Expression.Parameter(typeof(TFrom), "from");
var paramTo = Expression.Parameter(typeof(TTo), "to");
var expressionBlock =
Expression.Block(_fieldMaps
.Select(fm => Expression.Invoke(fm, paramFrom, paramTo))
.ToArray());
var lambda = Expression.Lambda<Action<TFrom, TTo>>(
expressionBlock,
paramFrom,
paramTo);
return lambda.Compile();
}
}