Наткнулся на очень интересный код:
using System.Linq.Expressions;
class FieldAccessor
{
private static readonly ParameterExpression fieldParameter = Expression.Parameter(typeof(object));
private static readonly ParameterExpression ownerParameter = Expression.Parameter(typeof(object));
public FieldAccessor(Type type, string fieldName)
{
var field = type.GetField(fieldName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field == null) throw new ArgumentException();
var fieldExpression = Expression.Field(
Expression.Convert(ownerParameter, type), field);
Get = Expression.Lambda<Func<object, object>>(
Expression.Convert(fieldExpression, typeof(object)),
ownerParameter).Compile();
Set = Expression.Lambda<Action<object, object>>(
Expression.Assign(fieldExpression,
Expression.Convert(fieldParameter, field.FieldType)),
ownerParameter, fieldParameter).Compile();
}
public Func<object, object> Get { get; }
public Action<object, object> Set { get; }
}
Автор утверждает, что он производительный стандартной рефлекссии и даже ответ отмечен, как принятый.
Однако, не понимаю, чем он лучше стандартного кеширования поля. Или это плацебо?
Здесь кэшируется не само поле, а метод доступа к нему. Подразумевается, что для каждого поля класса, которое требуется динамически устанавливать или читать, создаётся свой экземпляр класса FieldAccessor
. После этого созданный объект используется многократно. Если то же самое делать по старинке, выглядеть это будет так:
FieldInfo pi = type.GetField(fieldName, /* те же самые флаги */);
return pi.GetValue(object);
Этот вызов будет медленнее, чем динамически сгенерированный аксессор специально для указанного поля, т.к. через лямбда-выражение мы генерируем код, содержащий только обращение к полю так, как будто бы мы написали просто return fieldName
. Правда, он будет упакован в делегат, что всё равно даст некоторый overhead по сравнению с обычным полем. В принципе, в .NET 1 или 2, где ещё не было интерпретируемых запросов, такое тоже можно было сделать посредством генерации MSIL на Reflection.Emit
, но это гораздо сложнее. Возможность описания лямбда-выражения как структуры данных с последующей компиляцией делает то же самое гораздо проще.
Надо помнить, что получение поля по имени и тем более компиляция лямбда-выражения в MSIL - это операции не моментальные, поэтому выигрыш в производительности от использования такого класса мы получим только в том случае, когда мы создали один объект для каждого поля, а потом многократно его используем.
Виртуальный выделенный сервер (VDS) становится отличным выбором
На данный вопрос уже ответили:
Когда я копирую текст из TextBox(multiline) в строку, а потом пытаюсь из нее что-то удалить - со строкой НИЧЕГО не происходитВот часть кода:
На макете имеется DataGrid, у которого один столбец и одна ячейкаКак добавить ещё один (вложенный выходит) DataGrid в эту ячейку? Что-то такое:
получаю данный от Tcp сервера, если запрос длится более 1 сек, то завершаем Task ожидания получения ответа и выкидываем TimeoutException("