2013-07-15 5 views
5

У меня есть метод, который использует циклы через объекты 7,753+ и получает значение каждого свойства для каждого объекта. Каждый объект имеет 14 объектов.Можно ли ускорить этот метод?

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); 
    } 
} 

Я считаю GetValue это то, что занимает большую часть времени в этом методе, метод занимает около 900ms бежать, но GetValue, который называется 800,000+ раз занимает около 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; 
    } 
+0

Так что вы хотите, чтобы 'PropertyInfo.GetValue()' ускорялся? –

+0

Как долго длится эквивалентная версия без вызовов отражения? Это основные накладные расходы «GetValue», но мне интересно, сколько накладных расходов он добавляет по сравнению с прямой ссылкой на свойства. (1000 нс нетривиальны, но не огромны) – Guvante

+0

Известны ли типы объектов во время компиляции? Можете ли вы написать безопасные значения getters/formatters для каждого известного типа, и все, что вам нужно сделать, - это поиск типа/отбрасывание на каждый 'элемент', который будет создавать KeyValuePairs для вас и вообще избежать отражения? EDIT: Или еще лучше, чтобы ваши объекты реализовали интерфейс с помощью одного метода, задачей которого является возвращение набора KeyValuePairs; избегайте полного поиска/отливки. –

ответ

0

Я сделал простой тест, где я заменил проблематичную .GetValue с функцией исполняющей упрощенного ассигнования («если имя свойства является блабло, значение Object.blabla»). Тест состоит только из простой версии ваших функций/переменных/свойств и цикла, позволяющего полностью контролировать количество итераций. Результаты, безусловно, удивительно: новый подход в 10 раз быстрее! Имейте в виду, что в моих оригинальных тестах (50000 итераций) время было 2276 (старый) против 234 (новый). Эта разница остается постоянной для разных сценариев; например, для 8000 итераций, он обеспечивает 358 мс против 36 мс. Я провел эти тесты на довольно мощном компьютере и на winforms C#; @Xaisoft может взять код ниже, выполнить тест в соответствии с его конкретными условиями и сообщить результаты.

Код:

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 Примечание: Я хотел бы, чтобы люди поняли так впечатляющие результаты в более общем, чем только применительно к .GetValue. В наши дни компьютеры могут справляться с множеством вещей, и вам не нужно максимизировать производительность каждого отдельного бита, это правда. С другой стороны, если у вас проблемы с производительностью, и вам нужно «экономить ресурсы» более соответствующим образом, вы должны сосредоточить свои улучшения на идее «чем проще, тем быстрее». Я сделал себе улучшение производительности в кодах с использованием соответствующего количества Lists и Dictionaries, и результаты можно получить, даже после каждого отдельного изменения (List в обычный Array). Вам не нужно быть слишком пассивным на этом фронте, но в случае необходимости помните, что требования к потреблению памяти/связанного времени с List по отношению к Array выше (и оба элемента в основном одинаковы). То же самое для многомерных массивов, долго размера массивов и т.д.

------ ПОДРОБНЕЕ АНАЛИЗ ИСПОЛНЕНИЯ

Даже если я пусть моя точка очень ясно с самого начала (только идея, которая должен быть адаптирован к каждой ситуации), я понимаю, что мое требование (в 10 раз быстрее) действительно требует правильного определения. Я делаю тесты в разных условиях, и вот результаты:

ПРИМЕЧАНИЕ: вышеупомянутые результаты были выведены 32-битным исполняемым файлом; все перечисленные ниже - из 64-битного. Я наблюдал улучшение производительности .GetValue при переходе от 32-битного к 64-битовому. Обновление 64-разрядная версия результатов выше (мс):

     GetValue  Direct Assignation  
50000 iterations -> 1197     157 
80000 iterations -> 1922     253 
100000 iterations -> 2354     310 

Таким образом, коэффициент изменяется от 10 раз до 7,5 раз.

Я начал увеличивать количество свойств (каждый раз на 64-битных) и GetValue стал лучше и лучше.Результаты:

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 

Я не уверен, если улучшение GetValue продолжится и достигнет точки, где будет лучше, чем упрощенный подход, но кого это волнует? На этом этапе ясно, что все большее число свойств играет против упрощенного подхода, поэтому пришло время попробовать другую (опять же довольно упрощенную) альтернативу: глобальный массив, сохраняющий все свойства.

private static int[,] List0; 

Будучи заселен параллельно с заданным свойством (то есть, когда object.propX = any value соответствующих позиций в массиве также заполняется) и отнесено объекты/позиций свойств (первый объект, третья собственности, и т.д.). Логически это ограничивает количество объектов (рост первого измерения выше 1000 не рекомендуется), но вы можете полагаться на разные массивы (один хранится от первого объекта до 1000-го, другого от 1001-го до 2000-го , и т.д.); вы можете установить функцию, которая принимает в качестве аргумента имя объекта и возвращает соответствующий массив.

Изменения в главном цикле:

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]; 
    } 
} 

, запустив этот новый подход в случае, описанном выше, я получаю:

50 Properties 
         GetValue   2D Array  
    80000 iterations -> 6772    155 

Aver. ratio = 45.146 

еще один:

70 Properties 
          GetValue   2D Array  
    80000 iterations -> 10444    213 

Aver. ratio = 49.06 

И я остановился мои тесты здесь. Думаю, этого достаточно, чтобы доказать свою точку зрения.

Различные подходы обеспечивают различные характеристики в разных условиях и, таким образом, лучший способ узнать идеальную конфигурацию для конкретной ситуации - это проверить ее. Опираясь на предельную истину, редко является лучшим решением проблемы (хотя я могу ошибаться ... все еще жду ответа от Дмитрия, чтобы проверить его решение в разных условиях). Таким образом, в соответствии с проверенными условиями, кажется, что исходный упрощенный подход приемлем для случаев, когда количество свойств относительно невелико (т. Е. Ниже 20); выше этого, требуемое усилие hardcoding не кажется достойным, и полагаться на другую альтернативу (например, 2D-массив, который я предложил) лучше. В любом случае GetValue обеспечивает четкую производительность, которая может быть улучшена различными способами.

Я надеюсь, что мне не нужно будет обновлять этот ответ еще раз :)

+0

Что для меня отстой, так это то, что у одного из моих объектов есть еще 140 полей :( – Xaisoft

+0

Это, безусловно, проблема. Вся суть моего ответа - это просто идея. Вы должны придумать наиболее подходящую конфигурацию для каждой ситуации. Например, создание глобального массива, который не может быть лучшим подходом с точки зрения кодирования, ускорит некоторые ситуации (например, 140-полевое предложение, которое вы предлагаете). В любом случае, на данный момент , моя дрянная коррекция действительно обеспечивает гораздо более высокую производительность для этой функции, вы можете рассчитывать на нее в настоящее время, думая лучше всего ускорить весь алгоритм в лучшем виде. – varocarbas

+0

@ Xaisoft, насколько все приходят здесь с новыми идеями и помещением чисел на стол (и я шучу, говоря, что это дрянное и т. д.).), Я обновил свой ответ (последний абзац), чтобы подчеркнуть, что на самом деле представляет этот подход: 90% УЛУЧШЕНИЕ без каких-либо действий. Я предполагаю, что вы это получили, но на всякий случай ... Несколько раз я обманываюсь слишком много, и точка не передается должным образом. – varocarbas

2

Если проблема действительно в PropertyInfo.GetValue вызове метода вы можете использовать подход с построения кэш-добытчиками собственности (например, с помощью скомпилированных выражений). Вот образец, который demostrates, что этот подход до 30-40% быстрее, чем оригинальный метод на 8000 объектов с 14 свойствами (с горячей кэш-памяти):

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()); 
} 

Вот оригинал реализации (уменьшен для целей тестирования):

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); 
    } 
} 

Вот оптимизированная реализация:

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(); 
} 

испытаний класс:

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; } 
} 

Обновление: Добавлено решение от varocarbas в тестах

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(); 
} 

Консольные Результаты: (Release, x64) (Core i5 M560 @ 2,67 ГГц, 8 Гб оперативной памяти, Win7x64)

Reflection PropertyInfo.GetValue: 161288 
Cached Getters (Cold cache): 153808 
Cached Getters (Hot cache): 110837 
returnProps special method: 128905 

Таким образом, подход к кешированию является лучшим.

UPDATE2
Методы продемонстрированные в образце, предназначены для использования, когда тип objects элементов известно во время компиляции (общий путь):

InitializeData2<Obj>(...) 

При использовании объектов список, тип которого неизвестен во время компиляции, вы можете использовать следующий подход для вызова метода общего назначения InitializeData2<> во время выполнения:

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[] { }) }); 
} 
+0

Привет, когда я делаю изменения, он говорит мне этот метод: 'InitializeData (объекты, реквизиты, dataP, tod); Аргументы типа не могут быть выведены из использования. «Что-то не хватает? – Xaisoft

+0

Мои объекты не входят в список . Они входят как «Список list', а затем, чтобы получить свойства типа, я делаю' var objects = (IList) list [0]; Тип objType = objects [0] .GetType(); ' – Xaisoft

+0

@Xaisoft 1st- Вы можете указать его явно:' InitializeData2 (объекты, свойства, tod); ' 2nd - Во всяком случае, я не вижу проблем с каким-либо модификации моего примера ...И вы всегда можете уточнить свой вопрос или создать новый, чтобы продемонстрировать точную проблему. – DmitryG

7

Для вашего класса значений вы можете создать прямой сеттер и лямбда-приемник.
Производительность почти так же быстро, как прямой доступ к объектам. взято с http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html (немецкий текст).

Получить сеттер от PropertyInfo

var propertyInfo = typeof(MyType).GetProperty(MyFieldName); 
var setter = BuildUntypedSetter<T>(propertyInfo)); 

Использование в цикле

var myTarget = new MyType(); 
setter(myTarget, aNewValue) 

Помощник для быстрого извлечения Сеттера поглотитель

public static Action<T, object> BuildUntypedSetter<T>(PropertyInfo propertyInfo) 
{ 
    var targetType = propertyInfo.DeclaringType; 
    var methodInfo = propertyInfo.GetSetMethod(); 
    var exTarget = Expression.Parameter(targetType, "t"); 
    var exValue = Expression.Parameter(typeof(object), "p"); 
    var exBody = Expression.Call(exTarget, methodInfo, 
    Expression.Convert(exValue, propertyInfo.PropertyType)); 
    var lambda = Expression.Lambda<Action<T, object>>(exBody, exTarget, exValue); 
    var action = lambda.Compile(); 
    return action; 
} 

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; 
} 

============= Анализ производительности Добавлена ​​===================

5 Мио Объекты, 20 Свойства

  • 3.4s прямого доступа Свойство
  • 130.0s через PropertyInfo.SetValue
  • 4.0s через TypedSetter (код, показанный в статье)
  • 9.8s через UnTypedSetter (код выше)

Трюк состоит в том, чтобы сгенерировать свойство-setter и -getter один раз для каждого класса повторно использовать их.

// 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); 
    } 
} 
0

Продолжение поста выше: Ваш код создает словарь имени свойства и значения (отформатированный). Поэтому нам нужен только список в качестве входных данных. Из T мы можем получить всю информацию.

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; ; 
    } 

Метод BuildUntypedGetter(), как

// 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; 
    } 

Там нет необходимости указывать тип в вызове. Он определяется по типу вывода.

 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); 
Смежные вопросы