动态平面C#对象类运行时的属性列表

时间:2015-09-30 14:44:12

标签: c# dynamic reflection

我是这样的A类:

public class A
{
    private String id;              // Generated on server
    private DateTime timestamp;
    private int trash;
    private Humanity.FeedTypeEnum feedType
    private List<Property> properties;
// ...

其中Property是:

public class Property
{
    private Humanity.PropertyTypeEnum type;
    private string key;
    private object value;
//...

我想构建一个动态对象,将List<Property> properties A字段与原始属性相对应。例如:

A a = new A();
a.Id = "Id";
a.Timestamp = DateTime.Now;
a.Trash = 2;
a.FeedType = Humanity.FeedTypeEnum.Mail;
a.Properties = new List<Property>()
{
    new Property()
    {
        Type = Humanity.PropertyTypeEnum.String,
        Key = "name"
        Value = "file1.pdf"
    },
    new Property()
    {
        Type = Humanity.PropertyTypeEnum.Timestamp,
        Key = "creationDate",
        Value = Datetime.Now
    }
}

正如我所评论的那样,我想平放这个a对象,以便访问这些属性:

String name = a.Name;
DateTime creationDate = a.CreationDate;
a.Name = "otherName";
a.CreationDate = creationDate.AddDays(1);

我使用Reflection实现了这一点。但是,我发现使用ExpandoObject是最佳选择。

问题是,我怎样才能使用ExpandoObject类?

2 个答案:

答案 0 :(得分:2)

你可以做你想要的扩展DynamicObject类:

class A : System.Dynamic.DynamicObject
{
    // Other members
    public List<Property> properties;

    private readonly Dictionary<string, object> _membersDict = new Dictionary<string, object>();

    public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
    {
        result = null;
        if (!_membersDict.ContainsKey(binder.Name))
            return false;

        result = _membersDict[binder.Name];
        return true;
    }

    public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value)
    {
        if (!_membersDict.ContainsKey(binder.Name))
            return false;

        _membersDict[binder.Name] = value;
        return true;
    }

    public void CreateProperties()
    {
        foreach (Property prop in properties)
        {
            if (!_membersDict.ContainsKey(prop.key))
            {
                _membersDict.Add(prop.key, prop.value);
            }
        }
    }
}

然后像这样使用它:

A a = new A();
/////////
a.Properties = new List<Property>()
{
    new Property()
    {
        Type = Humanity.PropertyTypeEnum.String, // Now this property is useless, the value field has already a type, if you want you can add some logic around with this property to ensure that value will always be the same type
        Key = "name"
        Value = "file1.pdf"
    },
    new Property()
    {
        Type = Humanity.PropertyTypeEnum.Timestamp,
        Key = "creationDate",
        Value = Datetime.Now
    }
}
a.CreateProperties();
dynamic dynA = a;
dynA.name = "value1";

答案 1 :(得分:1)

此方法只是覆盖方括号运算符。不像你想要的那样光滑,但更简单,更实用。 你绝对不能像你描述的那样拥有设计时间(当你编写代码时)。 您可以在运行时使其与反射一起工作,但肯定不是您表现出来的方式吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            a.properties = new List<Property>()
            {
                new Property(Humanity.PropertyTypeEnum.String, "name", "file1.pdf"),
                new Property(Humanity.PropertyTypeEnum.Timestamp, "creationDate", DateTime.Now)
            };

            //String name = a.Name;
            //DateTime creationDate = a.CreationDate;
            //a.Name = "otherName";
            //a.CreationDate = creationDate.AddDays(1);

            String name = (String)a["name"];
            DateTime creationDate = (DateTime)a["creationDate"];
            a["name"] = "otherName";
            a["creationDate"] = creationDate.AddDays(1);
        }

        public class A
        {
            private Dictionary<Property, object> myvalues = new    Dictionary<Property, object>();
            public List<Property> properties;

            public object this[string name]
            {
                get
                {
                    var prop = properties.Find(p => p.key == name);
                    if (prop == null)
                        throw new Exception("property " + name + " not  found.");
                    return prop.value;
                }
                set
                {
                    var prop = properties.Find(p => p.key == name);
                    if (prop == null)
                        throw new Exception("property " + name + " not found.");
                    prop.value = value;
                }
            }
        }

        public class Property
        {
            public Property(Humanity.PropertyTypeEnum type, string key,     object value) { this.type = type; this.key = key; this.value =    value; }
            private Humanity.PropertyTypeEnum type;
            public string key;
            public object value;
        }
    }
}

namespace Humanity
{
    public enum PropertyTypeEnum { String, Timestamp };
    public enum FeedTypeEnum { };
}