如何将任何C#对象转换为ExpandoObject?

Gig*_*igi 6 c# dynamic expandoobject

我已经阅读了很多关于如何使用ExpandoObject通过添加属性从头开始动态创建对象的内容,但我还没有发现你是如何从已经拥有的非动态C#对象开始做同样的事情的.

例如,我有这个琐碎的课程:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Telephone { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想将它转换为ExpandoObject,以便我可以根据已经的内容添加或删除属性,而不是从头开始重建相同的东西.这可能吗?

编辑:标记为重复的问题显然不是这个问题的重复.

Val*_*rii 13

可以这样做:

var person = new Person { Id = 1, Name = "John Doe" };

var expando = new ExpandoObject();
var dictionary = (IDictionary<string, object>)expando;

foreach (var property in person.GetType().GetProperties())
    dictionary.Add(property.Name, property.GetValue(person));
Run Code Online (Sandbox Code Playgroud)

  • 有一点我想澄清这个解决方案,这不是使Person成为一个expando对象,而是将属性从Person复制到一个新的expando对象.如果你做`expando.Id = 2`,`person.Id`的值仍然是1 (4认同)
  • 说明:如果您查看 ExpandoObject,您可以看到它实现了`IDictionary&lt;string, object&gt;`。如果您在运行时观察对象,您可以看到一个“结果视图”,它是该字典的枚举。所以这里发生的事情是:您创建一个空的“ExpandoObject”,然后使用该对象的一个​​向上转换的实例来手动操作其 IDictionary Form。`expando` 对象被直接修改,即使看起来你只是在修改字典实例。最后,您已手动将属性添加到 `expando` 实例。 (2认同)

Sco*_*ain 9

您不能将Person类“转换”为 expando 对象。但是,您可以创建一个DynamicObject包含 aPerson并转发所有字段的包装器。

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Reflection;

namespace SandboxConsole
{
    public class ExpandoWrapper : DynamicObject
    {
        private readonly object _item;
        private readonly Dictionary<string, PropertyInfo> _lookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCulture);
        private readonly Dictionary<string, PropertyInfo> _ignoreCaseLookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase);

        private readonly Dictionary<string, Box> _lookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCulture);
        private readonly Dictionary<string, Box> _ignoreCaseLookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCultureIgnoreCase);

        private class Box
        {
            public Box(object item)
            {
                Item = item;
            }
            public object Item { get; }
        }

        public ExpandoWrapper(object item)
        {
            _item = item;
            var itemType = item.GetType();
            foreach (var propertyInfo in itemType.GetProperties())
            {
                _lookup.Add(propertyInfo.Name, propertyInfo);
                _ignoreCaseLookup.Add(propertyInfo.Name, propertyInfo);
            }
        }
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = null;
            PropertyInfo lookup;
            if (binder.IgnoreCase)
            {
                _ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
            }
            else
            {
                _lookup.TryGetValue(binder.Name, out lookup);
            }

            if (lookup != null)
            {
                result = lookup.GetValue(_item);
                return true;
            }

            Box box;
            if (binder.IgnoreCase)
            {
                _ignoreCaseLookupExtra.TryGetValue(binder.Name, out box);
            }
            else
            {
                _lookupExtra.TryGetValue(binder.Name, out box);
            }

            if (box != null)
            {
                result = box.Item;
                return true;
            }

            return false;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            PropertyInfo lookup;
            if (binder.IgnoreCase)
            {
                _ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
            }
            else
            {
                _lookup.TryGetValue(binder.Name, out lookup);
            }

            if (lookup != null)
            {
                lookup.SetValue(_item, value);
                return true;
            }

            var box = new Box(value);
            _ignoreCaseLookupExtra[binder.Name] = box;
            _lookupExtra[binder.Name] = box;

            return true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

using System;

namespace SandboxConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            var person = new Person() {Id = 1};
            dynamic wrapper = new ExpandoWrapper(person);

            wrapper.Id = 2;
            wrapper.NewField = "Foo";

            Console.WriteLine(wrapper.Id);
            Console.WriteLine(person.Id);
            Console.WriteLine(wrapper.NewField);
        }
    }
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public string Telephone { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在这个例子中,`JsonConvert.SerializeObject(wrapper)` 变成了 `{}`。 (2认同)