Здравствуйте.
Нужно постоянно читать/устанавливать значение свойства объекта через reflection.
Имеет ли смысл сделать кэш метаданных для увеличения скорости, вроде такого:
class MyClass
{
private Object _target;
private PropertyInfo _targetProperty;
public MyClass(Object target)
{
_target = target;
_targetProperty = _target.GetType().GetProperty(...);
}
public void Foo()
{
_targetProperty.SetValue(_target, ...);
}
}
или все уже придумано до нас и можно со спокойной совестью делать так:
class MyClass
{
private Object _target;
public MyClass(Object target)
{
_target = target;
}
public void Foo()
{
_target.GetType().GetProperty(...).SetValue(_target, ...);
}
}
?
FW4, если это имеет значение. Желательно с пруфлинком.
Здравствуйте, HowardLovekraft, Вы писали:
HL>Нужно постоянно читать/устанавливать значение свойства объекта через reflection. HL>Имеет ли смысл сделать кэш метаданных для увеличения скорости, вроде такого:
Если речь об оптимизациях, то надо сказать о целях оптимизации. Сделайте без кеша — удовлетворит или нет? Сделайте с кешем. Сравните.
Для примера: дефолтовая реализация TypeDescriptionProvider, работающая через рефлекшен, кэширует у себя некоторые результаты и в большинстве случаев этого более чем достаточно. Но в некоторых операциях имеет смысл самому закешировать результат, что бы съэкономить на обращениях к тому внутреннему кешу :о)
Точно так же и тут: посмотрите, удовлетворит ли вас производительность без присиданий и, если нет, то удовлетворят ли приседания. А то я вам скажу — нет, не делайте, там внутри конечно всё в некотором роде закешироано да и работает ("в моих кейсах") достаточно быстро. А вы попробуете у себя и скажите "ан нет, врёшь: если закешировать, у меня втрое быстрее получается". А у меня может хоть в десять раз медленнее, всё равно без микроскопа не разглядеть?
Help will always be given at Hogwarts to those who ask for it.
Скорее, вопрос про существование кэша в недрах рантайма — в принципе он есть или нет, и если есть, то что там кэшируется и при каких условиях. Интересуют именно результаты Object.GetType, Type.GetProperty, Type.GetMethod.
Я понимаю, что итоговая реализация будет сильно зависеть от вариантов использования и, возможно, свой кэш не понадобится.
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте. HL>Нужно постоянно читать/устанавливать значение свойства объекта через reflection. HL>Имеет ли смысл сделать кэш метаданных для увеличения скорости, вроде такого:
Имеет — я специально для такого варианта писал примитивный враппер и хранил в нём делегаты на геттер и сеттер (созданные через Delegate.Create (или как там его)).
Какие грабли я таким образом решал, точно не помню, но производительность от него точно не ухудшилась. Если интересует, завтра могу скинуть код.
В теории скорость должна приблизиться к emit-у, если нет, можно сгенерить код самому, благо System.Linq.Expressions сделали это дело до неприличия простым.
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте. HL>Нужно постоянно читать/устанавливать значение свойства объекта через reflection. HL>Имеет ли смысл сделать кэш метаданных для увеличения скорости, вроде такого: HL>? HL>FW4, если это имеет значение. Желательно с пруфлинком.
Имеет (в том числе для FW4), при частом чтении/записи разница заметна невооружённым взглядом. Сам недано с таким сталкивался. Код не дам (NDA), но тесты должны быть тривиальны.
Ещё, при большом желании, можно вобще избавиться от Reflection'а и генерировать код чтения/записи, например, через Linq.Expressions, разница в скорости тоже достигает нескольких раз.
Здравствуйте, k.o., Вы писали:
KO>при большом желании, можно вобще избавиться от Reflection'а и генерировать код чтения/записи, например, через Linq.Expressions
Ткните, пожалуйста, в место, где об этом можно почитать (генерация код чтения/записи через expressions).
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте, k.o., Вы писали:
KO>>при большом желании, можно вобще избавиться от Reflection'а и генерировать код чтения/записи, например, через Linq.Expressions HL>Ткните, пожалуйста, в место, где об этом можно почитать (генерация код чтения/записи через expressions).
Здравствуйте, k.o., Вы писали:
KO>Ещё, при большом желании, можно вобще избавиться от Reflection'а и генерировать код чтения/записи, например, через Linq.Expressions, разница в скорости тоже достигает нескольких раз.
Не надо тут никакого Linq.Expressions. Это как из пушки по воробьям. Для чтения свойств и вызова методов отлично подходят делегаты. Sinix прав
. Через рефлксию получаете проперти-инфо, через них метод-инфо, и Delegate.Create() получаете ссылку на делегат. Вот ее и прикапывайте. Скорость будет чуть хуже чем у виртуального вызова, т.е. ахринительная. Быстрее не добиться. Вот пример кода:
using System;
using System.Text;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
const string methodName = "Length";
var a = new StringBuilder("test");
object obj = a;
var getter = MakeGetterDelegate<int>(obj, methodName);
var setter = MakeSetterDelegate<int>(obj, methodName);
Console.WriteLine(getter());
setter(5);
Console.WriteLine(a.Length);
Console.WriteLine("'" + a + "'");
}
static Action<T> MakeSetterDelegate<T>(object obj, string propertyName)
{
var setter = obj.GetType().GetProperty(propertyName).GetSetMethod(true);
var result = Delegate.CreateDelegate(typeof(Action<T>), obj, setter);
return (Action<T>)result;
}
static Func<T> MakeGetterDelegate<T>(object obj, string propertyName)
{
var getter = obj.GetType().GetProperty(propertyName).GetGetMethod(true);
var result = Delegate.CreateDelegate(typeof(Func<T>), obj, getter);
return (Func<T>)result;
}
}
выводит:
4
5
'test '
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, k.o., Вы писали:
KO>>Ещё, при большом желании, можно вобще избавиться от Reflection'а и генерировать код чтения/записи, например, через Linq.Expressions, разница в скорости тоже достигает нескольких раз.
VD>Не надо тут никакого Linq.Expressions. Это как из пушки по воробьям.
Во-первых см. выделенное.
VD>Для чтения свойств и вызова методов отлично подходят делегаты. Sinix прав
. Через рефлксию получаете проперти-инфо, через них метод-инфо, и Delegate.Create() получаете ссылку на делегат. Вот ее и прикапывайте. Скорость будет чуть хуже чем у виртуального вызова, т.е. ахринительная. Быстрее не добиться. Вот пример кода:
Во-вторых, твой код и мой не эквивалентны. Моему не нужно знать тип свойства на этапе компиляции и он может работать с разными объектами, зато твой должен быть быстрее. Нужен-ли кому-нибудь такой функционал? Мне, например, ни Linq.Expression ни этих делегатов не понадобилось — хватило скорости PropertyInfo.GetValue/SetValue, а ТС пусть сам решает, что ему нужно.
Здравствуйте, k.o., Вы писали:
KO>Моему не нужно знать тип свойства на этапе компиляции и он может работать с разными объектами
Кстати, да. У меня на входе — сферический объект в вакууме.