Альтернативный подход состоит в том, чтобы использовать DynamicObject
вместо ExpandoObject
, и таким образом у вас есть только накладные расходы на выполнение отражения, если вы действительно пытаетесь получить доступ к свойству из другого объекта.
public class DynamicForwarder : DynamicObject
{
private object _target;
public DynamicForwarder(object target)
{
_target = target;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
var prop = _target.GetType().GetProperty(binder.Name);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(_target, null);
return true;
}
}
Теперь это отражается только на том, что вы пытаетесь получить доступ к свойству через динамический get. С другой стороны, если вы повторно обращаетесь к одному и тому же свойству, он должен делать отражение каждый раз. Таким образом, вы можете кэшировать результат:
public class DynamicForwarder : DynamicObject
{
private object _target;
private Dictionary _cache = new Dictionary();
public DynamicForwarder(object target)
{
_target = target;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// check the cache first
if (_cache.TryGetValue(binder.Name, out result))
return true;
var prop = _target.GetType().GetProperty(binder.Name);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(_target, null);
_cache.Add(binder.Name, result); // <-------- insert into cache
return true;
}
}
Вы могли бы поддержать сохранение списка целевых объектов для объединения своих свойств и поддержки свойств настройки (с аналогичным переопределением, называемым TrySetMember ), чтобы вы могли динамически устанавливать значения в словаре кеша.
Конечно, накладные расходы на размышления, вероятно, не стоит беспокоиться, но для больших объектов это может ограничить его влияние. Что может быть более интересно, так это дополнительная гибкость, которую это дает вам.