IDynamicMetaObjectProvider 设置 属性 使用文字名称

IDynamicMetaObjectProvider set property using literal name

我需要使用字符串 属性Name 设置 DynamicObject 属性。我找到了使用此 answer 获取 属性 值的方法,但是当涉及到 setValue 时,我不太确定如何重写代码以设置 属性。我收到运行时错误并且不太确定表达式逻辑。我想知道您是否可以提出任何关于如何实施 void SetProperty(object o, string member,object value) 方法的想法。

在某些情况下,例如ExpandoObject,那么您可以使用IDictionary<string,object> API代替:

ExpandoObject obj = ...
var dict =  (IDictionary<string, object>)obj;
object oldVal = dict[memberName];
dict[memberName] = newVal;

在更一般的情况下 IDynamicMetaObjectProvider:您可以从 FastMember 借用 CallSiteCache

internal static class CallSiteCache
{
    private static readonly Hashtable getters = new Hashtable(), setters = new Hashtable();

    internal static object GetValue(string name, object target)
    {
        CallSite<Func<CallSite, object, object>> callSite = (CallSite<Func<CallSite, object, object>>)getters[name];
        if (callSite == null)
        {
            lock (getters)
            {
                callSite = (CallSite<Func<CallSite, object, object>>)getters[name];
                if (callSite == null)
                {
                    CallSite<Func<CallSite, object, object>> newSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, name, typeof(CallSiteCache), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
                    getters[name] = callSite = newSite;
                }
            }
        }
        return callSite.Target(callSite, target);
    }
    internal static void SetValue(string name, object target, object value)
    {
        CallSite<Func<CallSite, object, object, object>> callSite = (CallSite<Func<CallSite, object, object, object>>)setters[name];
        if (callSite == null)
        {
            lock (setters)
            {
                callSite = (CallSite<Func<CallSite, object, object, object>>)setters[name];
                if (callSite == null)
                {
                    CallSite<Func<CallSite, object, object, object>> newSite = CallSite<Func<CallSite, object, object, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, name, typeof(CallSiteCache), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
                    setters[name] = callSite = newSite;
                }
            }
        }
        callSite.Target(callSite, target, value);
    }
}

请注意,我们 可以 target 键入 IDynamicMetaObjectProvider,但我们实际上并不需要 - CallSite API 不需要它。