C#动态类

时间:2011-03-14 01:34:53

标签: c#

我在谈论与dynamic类似的事情。 This没有回答我的问题,因此这个问题。我希望有一个类,我可以在运行时添加属性。它需要从类型object继承。

我见过继承自DynamicObject,但没有说明如何在运行时添加属性。我可以为此解决一些问题吗?

我有一个这样的课程:

public class SomeModel : DynamicObject {
       public string SomeMandatoryProperty {get; set;}
}

我想在运行时将另一个类的所有属性添加到此类。所以例如。

SomeModel m = new SomeModel();
m = someOtherClass;
string hi = m.otherClassProp; //Property from other class is added.
string mandatory = m.SomeMandatoryProperty; //From the mandatory property set previously.

3 个答案:

答案 0 :(得分:3)

我认为您正在寻找ExpandoObject

  

ExpandoObject类使您能够   添加和删​​除其成员   运行时的实例,也可以设置   并获得这些成员的价值观。这个   class支持动态绑定   使您可以使用标准语法   比如sampleObject.sampleMember   比较复杂的语法   sampleObject.GetAttribute( “sampleMember”)。

dynamic manager;

manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;

答案 1 :(得分:2)

您应该可以使用ExpandoObject代替。 ExpandoObject可以在运行时添加或删除成员,如果要转换为XML等,则可以提供非常好的支持。

来自MSDN文档:

    dynamic employee, manager;

    employee = new ExpandoObject();
    employee.Name = "John Smith";
    employee.Age = 33;

    manager = new ExpandoObject();
    manager.Name = "Allison Brown";
    manager.Age = 42;
    manager.TeamSize = 10;

答案 2 :(得分:1)

您可以使用ExpandoObject,因为您可以根据需要动态添加属性。但是,没有一种直接的方法可以轻松地使用来自另一个对象的值填充实例。您必须使用反射手动添加它。

你想编写一个包装器对象,你可以在仍然访问内部的同时添加属性吗?您可能需要考虑这种方式,您不必在两个不同的对象实例之间管理两个值的副本。我编写了一个测试类来包装字符串对象,以演示如何执行此操作(类似于ExpandoObject的工作方式)。它应该让您了解如何为您的类型执行此操作。

class DynamicString : DynamicObject
{
    static readonly Type strType = typeof(string);
    private string instance;
    private Dictionary<string, object> dynProperties;
    public DynamicString(string instance)
    {
        this.instance = instance;
        dynProperties = new Dictionary<string, object>();
    }
    public string GetPrefixString(string prefix)
    {
        return String.Concat(prefix, instance);
    }
    public string GetSuffixString(string suffix)
    {
        return String.Concat(instance, suffix);
    }
    public override string ToString()
    {
        return instance;
    }
    public override bool TryConvert(ConvertBinder binder, out object result)
    {
        if (binder.Type != typeof(string))
            return base.TryConvert(binder, out result);
        result = instance;
        return true;
    }
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        var method = strType.GetMethod(binder.Name, args.Select(a => a.GetType()).ToArray());
        if (method == null)
        {
            result = null;
            return false;
        }
        result = method.Invoke(instance, args);
        return true;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var members = strType.GetMember(binder.Name);
        if (members.Length > 0)
        {
            var member = members.Single();
            switch (member.MemberType)
            {
            case MemberTypes.Property:
                result = ((PropertyInfo)member).GetValue(instance, null);
                return true;
                break;
            case MemberTypes.Field:
                result = ((FieldInfo)member).GetValue(instance);
                return true;
                break;
            }
        }
        return dynProperties.TryGetValue(binder.Name, out result);
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        var ret = base.TrySetMember(binder, value);
        if (ret) return true;
        dynProperties[binder.Name] = value;
        return true;
    }
}

如果您想要冒险,可以定义自己的元对象来处理绑定。您最终可以获得不同类型的可重用元对象,并极大地简化您的代码。到目前为止,我已经玩了一段时间了。它还没有处理动态添加属性。我不会再进一步​​研究这个问题,但我会把它留在这里作为参考。

class DynamicString : DynamicObject
{
    class DynamicStringMetaObject : DynamicMetaObject
    {
        public DynamicStringMetaObject(Expression parameter, object value)
            : base(parameter, BindingRestrictions.Empty, value)
        {
        }
        public override DynamicMetaObject BindConvert(ConvertBinder binder)
        {
            if (binder.Type == typeof(string))
            {
                var valueType = Value.GetType();
                return new DynamicMetaObject(
                    Expression.MakeMemberAccess(
                        Expression.Convert(Expression, valueType),
                        valueType.GetProperty("Instance")),
                    BindingRestrictions.GetTypeRestriction(Expression, valueType));
            }
            return base.BindConvert(binder);
        }
        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
        {
            System.Diagnostics.Trace.WriteLine(String.Format("BindGetMember: {0}", binder.Name));
            var valueType = Value.GetType();
            var self = Expression.Convert(Expression, valueType);
            var valueMembers = valueType.GetMember(binder.Name);
            if (valueMembers.Length > 0)
            {
                return BindGetMember(self, valueMembers.Single());
            }
            var members = typeof(string).GetMember(binder.Name);
            if (members.Length > 0)
            {
                var instance =
                    Expression.MakeMemberAccess(
                        self,
                        valueType.GetProperty("Instance"));
                return BindGetMember(instance, members.Single());
            }
            return base.BindGetMember(binder);
        }
        private DynamicMetaObject BindGetMember(Expression instance, MemberInfo member)
        {
            return new DynamicMetaObject(
                Expression.Convert(
                    Expression.MakeMemberAccess(instance, member),
                    typeof(object)),
                BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
            );
        }
    }
    public string Instance { get; private set; }
    public DynamicString(string instance)
    {
        Instance = instance;
    }
    public override DynamicMetaObject GetMetaObject(Expression parameter)
    {
        return new DynamicStringMetaObject(parameter, this);
    }
    public override string ToString()
    {
        return Instance;
    }
    public string GetPrefixString(string prefix)
    {
        return String.Concat(prefix, Instance);
    }
    public string GetSuffixString(string suffix)
    {
        return String.Concat(Instance, suffix);
    }
}