ExpandoObject 添加 属性 和 "extra"-code

ExpandoObject add Property with "extra"-code

我读过一些关于 ExpandoObject 的资料,我可以用属性、字段、方法来扩展它。

//that's how to add a property to an ExpandoObject.
dynamic x = new ExpandoObject();
x.NewProp = string.Empty;

但有时,添加 属性 和一些 "extra-code" 会很方便。

class sample
{
    // a sample field.
    public string sampleString{get;set}
    // a sample property with some "extra code"
    private string s;
    public string sampleExtraString
    { 
         get{return s;}
         set{s=value;Console.WriteLine(s);}
    }
}

现在我的问题是,如何将 属性 添加到 ExpandoObject 以在片场执行我的 Console.WriteLine(s); 示例。

ExpandoObject 实现 INotifyPropertyChanged,如 here
所述 (在页面底部)

((INotifyPropertyChanged)x).PropertyChanged +=
        new PropertyChangedEventHandler(Expando_PropertyChanged);
    x.NewProp = string.Empty;


private static void Expando_PropertyChanged(object sender,
    PropertyChangedEventArgs e)
{
    Console.WriteLine("{0} has changed.", e.PropertyName);
}

我认为更好的方法是使用 DynamicObject,您可以拦截对
方法和属性的调用。
这是一个简单的例子,一个更健壮的例子不会使用反射在 属性 上执行 set/get 操作,而是使用 reflection.Emit 或任何编译操作策略。

public class Sample
{
    public string SampleExtraString { get; set; }
}

public class Factory
{
    public class ExtraPropertyObject<T> : DynamicObject
    {
        private readonly T instance = default(T);
        private readonly Type instanceType = null;

        public ExtraPropertyObject(T instance) {
            this.instance = instance;
            instanceType = instance.GetType();
        }

        public override bool TrySetMember(SetMemberBinder binder, object value) {
            PropertyInfo prop = null;

            if (binder.Name.Equals("SampleExtraString")) {
                Console.WriteLine(value);
            }

            prop = instanceType.GetProperty(binder.Name);

            if (prop != null) {
                try {
                    prop.SetValue(instance, value);
                    return true;
                }
                catch (Exception ex) {

                }
            }

            return false;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result) {
            var prop = instanceType.GetProperty(binder.Name);

            if (prop != null) {
                try {
                    result = prop.GetValue(instance);
                    return true;
                }
                catch (Exception ex) {

                }
            }

            result = null;
            return false;
        }
    }

    public static dynamic CreateInstance<TInstance>() where TInstance : class, new() {
        return new ExtraPropertyObject<TInstance>(new TInstance());
    }

    public static dynamic CreateInstance<TInstance>(TInstance instance) {
        return new ExtraPropertyObject<TInstance>(instance);
    }
}

class Program
{
    static void Main(string[] args) {
        var instance = Factory.CreateInstance<Sample>();
        instance.SampleExtraString = "value";
        Console.WriteLine("Get Operation: {0}", instance.SampleExtraString);
    }
}