Am a beginner in C# language
I have a class like
public class Plan
{
int a;
int b;
int c;
}
Can in any way I get the nth property of the class.
for eg: planObject.propertyIndex
This would be of great help for my project, as I am getting index number denoting the property whose value is to be changed. What I am doing right now is using if...else .
if(index ==1)
{
planObject.a = 100;
}
else if(index ==2)
{
planObject.b = 100;
}
Is there any other solution for this by using reflection?
You could use reflection, however, i would strongly advise against. Instead use a collection like List<int> or int[]. In this case, since you want to get the nth int value, you could also use a Dictionary<int, int>:
public class Plan
{
Dictionary<int, int> Values;
public Plan()
{
Values = new Dictionary<int, int>();
Values.Add(1, 100);
Values.Add(2, 200);
Values.Add(3, 300);
}
// ...
}
Now you can access the value by the number:
int value = Values[1]; // 100
Here's a list version:
public class Plan
{
List<int> Values = new List<int>();
public Plan()
{
Values.Add(100);
Values.Add(200);
Values.Add(300);
}
// ...
}
You access it via (zero based) index:
int value = Values[0]; // 100
A word of WARNING, this is in no way for beginners at all. And it might just make the code more complex. This answer takes for granted that you have a working knowledge of extension methods and reflection.
public static class PlanExtension
{
PropertyInfo _info = typeof(Plan).GetProperties();
public static void SetValue(this Plan plan, int index, int value)
{
var prop = _info[index - 1]; // So 1 maps to 0.. or 1 in this case
prop.SetValue(plan, value, null);
}
public static int GetValue(this Plan plan, int index)
{
var prop = _info[index - 1]; // Mapping magic
return (int) prop.GetValue(plan, null);
}
}
Called like this:
var p = new Plan();
p.SetValue(1, 139); // "a"
var b = p.GetValue(2); // "b"
It would help if you had a definable order to the properties, like name or something. Also, error handling is a must when it comes to reflection.
There's no "property by index" feature, but one approach that would make consumption easier would be to build an indexer on the class and encapsulate the switch statement there. Maybe something like this:
public class Plan
{
public int this[int index]
{
get
{
switch (index)
{
case 1:
return this.a;
...
}
}
set
{
switch (index)
{
case 1:
this.a = value;
...
}
}
}
}
So, now using it looks like this:
planObject[i] = 100;
Now, in your case it looks like you have an additional need because you have a key (the index) and a value (e.g. 100), so you need to store your keys and values in a Dictionary. So, in your class that uses Plan create a private field:
private Dictionary<int, int> _values = new Dictionary<int, int>
{
{ 1, 100 },
{ 2, 200 },
...
}
To use the dictionary you'd do something like this:
planObject[i] = _values[i];
UPDATE: if you can't change the class Plan then you'll need to do something like this. First you need a map from index to property name:
private Dictionary<int, string> _properties = new Dictionary<int, string>
{
{ 1, "a" },
{ 2, "b" },
...
}
and next you'll need to set that property:
var t = planObject.GetType();
var p = t.GetProperty(_properties[i]);
if (p != null)
{
p.SetValue(planObject, 100);
}
If you must use the object, instead of suggested Collections.
Plan b = new Plan();
Type t = new Type(b.GetType());
var properties = t.GetProperties();
for(int index = 0; index < properties.Length; index++)
{
properties[index].SetValue(b, 100);
}
Instead of using loop, you can pass your own index in properties array.
I hope it helps.
Here is what you want
public class Foo
{
public int A {get;set;}
public string B {get;set;}
public object GetPropertyValueAt(int index)
{
var prop = this.GetType().GetProperties()[index];
return prop.GetValue(this, null);
}
}
Usage
Foo foo = new Foo() {A = 1, B = "abc"};
int valueA = (int)foo.GetPropertyValueAt(0);
string valueB = (string)foo.GetPropertyValueAt(1);
int valueUnknown = (int)foo.GetPropertyValueAt(2); //<--- this line will give you an exception.
I am using VS2010 and EF4.0. The goal is to select fields of any IEnumerable, in order to show in the DataGridView. Take Northwind.Employees as example, the following code is OK.
private void button1_Click(object sender, EventArgs e)
{
NorthwindEntities en = new NorthwindEntities();
dataGridView1.DataSource = SelectNew(en.Employees, new string[] { "EmployeeID", "FirstName" });
}
public object SelectNew(object items, string[] fields)
{
IEnumerable<Employee> ems = items as IEnumerable<Employee>;
return ems.Select(em => new
{
id = em.EmployeeID,
name = em.FirstName
}
).ToArray();
}
The parameter object items is IEnumerable of EntityObject, and the function will be executed at client side memorry and shall have nothing to do with database now.
But I don't know the EntityObject type (Employee) until runtime, so maybe some complex reflection will be used.
I have checked this,
but when I bind the result to the control, it showed only blank rows without any column or data. And the funciton is for IQueryable, I have tried IEnumerable.AsQueryable and pass to it, but the results did not show any column either.
I've modified the example I pointed to in my comment above. This actually returns an IEnumerable<Dictionary<string,object>>, where each Dictionary represents one of the "new objects", and each key value pair in the dictionary represents a property and its value. Perhaps you can modify this for your use?
I'm not sure if you can simply bind the result to the DataGrid, but you should be able to figure it out.
I don't believe it's possible to create an anonymous type on the fly... But it might be possible to change this to use a dynamic type like ExpandoObject instead of a Dictionary. See this question for some hints on how to do that. I've never used dynamic objects, so you're on your own there!
public class TestClassA {
public string SomeString { get; set; }
public int SomeInt { get; set; }
public TestClassB ClassB { get; set; }
}
public class TestClassB {
public string AnotherString { get; set; }
}
public class Program {
private static void Main(string[] args) {
var items = new List<TestClassA>();
for (int i = 0; i < 9; i++) {
items.Add(new TestClassA {
SomeString = string.Format("This is outer string {0}", i),
SomeInt = i,
ClassB = new TestClassB { AnotherString = string.Format("This is inner string {0}", i) }
});
}
var newEnumerable = SelectNew(items, new string[] { "ClassB.AnotherString" });
foreach (var dict in newEnumerable) {
foreach (var key in dict.Keys)
Console.WriteLine("{0}: {1}", key, dict[key]);
}
Console.ReadLine();
}
public static IEnumerable<Dictionary<string, object>> SelectNew<T>(IEnumerable<T> items, string[] fields) {
var newItems = new List<Dictionary<string, object>>();
foreach (var item in items) {
var dict = new Dictionary<string, object>();
foreach (var field in fields)
dict[field] = GetPropertyValue(field, item);
newItems.Add(dict);
}
return newItems;
}
private static object GetPropertyValue(string property, object o) {
if (property == null)
throw new ArgumentNullException("property");
if (o == null)
throw new ArgumentNullException("o");
Type type = o.GetType();
string[] propPath = property.Split('.');
var propInfo = type.GetProperty(propPath[0]);
if (propInfo == null)
throw new Exception(String.Format("Could not find property '{0}' on type {1}.", propPath[0], type.FullName));
object value = propInfo.GetValue(o, null);
if (propPath.Length > 1)
return GetPropertyValue(string.Join(".", propPath, 1, propPath.Length - 1), value);
else
return value;
}
}
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);
If I have an Effect collection that's IEnumerable<Effect>, how do I set their .Name property based on their location in the collection?
So in the end, I just want them to be renamed starting from 1 to n.
<inside the collection>
effectInstance1.Name = Effect 1;
effectInstance2.Name = Effect 2;
effectInstance3.Name = Effect 3;
...
Is this possible with Linq?
LINQ isn't really intended for mutation anyway; however, you could use something like the Select overload that includes the index. But to be honest? Just loop and keep a counter. Much easier to understand, and that matters.
int position = 0;
foreach(var obj in collection) {
position++;
obj.Name = "Effect " + position.ToString();
}
var n = 0;
collection.ForEach(x=>x.Name = "Effect {0}".FormatWith(++n));
These are simple extension methods I bodged up back in 3.5:
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> lambda)
{
foreach(var element in collection)
lambda(element);
}
public static string FormatWith(this string base, params object[] args)
{
return String.Format(base, args);
}
It is not the best thing to solve with LINQ, but is possible:
class Program
{
private class Effect
{
public string Name { get; set; }
}
static void Main(string[] args)
{
List<Effect> list = new List<Effect> {new Effect(), new Effect(), new Effect()};
var newElements = list.Select((element, index) =>
{
element.Name = "Effect " + index.ToString();
return element;
});
foreach (var effect in newElements)
{
Console.WriteLine(effect.Name);
}
}
}
Outputs:
Effect 0
Effect 1
Effect 2