1

Я пытаюсь сократить расходы производительности вызова Activator.CreateInstance() на каждой итерации цикла следующего (упрощенно):Составитель Lambda и Activator.CreateInstance()

foreach (DataRow dr in chunk.Rows) 
{ 
    var objectToInsert = Activator.CreateInstance(type); 
} 

Основываясь на том, что Я прочитал, что лучше всего это сделать, чтобы собрать делегат и кешировать его. Это замедлит работу на первой итерации (в то время как делегат будет построен), но значительно улучшит производительность при последующих итерациях. Это приемлемо, так как я повторяю более 1000 раз. Чтобы еще больше усложнить ситуацию, я выполняю этот цикл параллельно, поэтому любой механизм кэширования должен быть потокобезопасным (ConcurentDictionary). Приведение метода в цикл в общий невозможен, так как тип, который я передаю в Activator.CreateInstance(), определяется выбором, сделанным пользователем через GUI и переданным моей функции. Для некоторых ссылок здесь является метод подписи:

public static void InsertByTable(IEnumerable<DataTable> chunkedTable, Type type) 

Так что я хочу сделать что-то вроде как это (это псевдо-код):

private static readonly ConcurrentDictionary<Type, Func<object>> CachedConstructors = 
     new ConcurrentDictionary<Type, Func<object>>(); 

private static object CreateInstance(Type type) 
{ 
    if (type == null) 
     return; 

    var constructor = CachedConstructors.GetOrAdd(type, BuildInstance); 

    constructor(type); 
} 

private static Func<Type> BuildInstance(Type type) 
{ 
} 

Но я вроде в догадках, как на самом деле построить выражение или даже если это правильный подход.

+1

Это будет зависеть от контекста, в котором вы ведете свой код, но если 'type' известно во время компиляции, вы можете изменить метод в родовой один, как' AddRows (...), где T: new() ', тогда вы могли бы просто использовать' new T() 'вместо' Activator.CreateInstance (...) '... –

+0

Я обновляю сообщение, чтобы включить всю функцию. В настоящее время я передаю тип в качестве параметра, поскольку тип определяется на основе параметров, которые пользователи выбирают через графический интерфейс. – jdm5310

ответ

1

Я думаю, что создание выражения - это способ пойти в этом случае. Для каждой строки, которую вы проходите, вы используете рефлексию для создания своих объектов. Это не будет дешево. Если вы создали выражение для инициализации объектов, вы платите за создание выражения один раз и остаетесь лямбдой, которая будет работать значительно лучше.

Func<DataRow, object> CreateInitializer(DataTable table, Type type) 
{ 
    var param = Expression.Parameter(typeof(DataRow), "row"); 
    var body = Expression.MemberInit(
     Expression.New(type), 
     from DataColumn c in table.Columns 
     let prop = type.GetProperty(c.ColumnName) 
     let value = Expression.Convert(
      Expression.Property(param, "Item", Expression.Constant(c.ColumnName)), 
      prop.PropertyType 
     ) 
     select Expression.Bind(prop, value) 
    ); 
    var expr = Expression.Lambda<Func<DataRow, object>>(body, param); 
    return expr.Compile(); 
} 

Затем, чтобы использовать его, просто создайте его один раз и используйте его для сопоставления строк.

var initializer = CreateInitializer(table, typeof(SomeObject)); 
var data = table.AsEnumerable().Select(initializer).ToList();