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

时间:2017-10-26 07:32:16

标签: c# dynamic expandoobject

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

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

<div class="cols">

  <div class="sectionOne">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </div>
  <div class="sectionTwo">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum, aliquam magna non, vestibulum nibh. Curabitur in eros ornare, ultricies tellus
    et, venenatis dolor.
  </div>
  <div class="sectionThree">
    Cras eget lectus non dolor congue dapibus in id massa. Nullam porta est accumsan lacinia tempus. Curabitur convallis ex nec vestibulum semper. Vivamus lorem
  </div>


  <div class="sectionOne">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </div>
  <div class="sectionTwo">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum, aliquam magna non, vestibulum nibh. Curabitur in eros ornare, ultricies tellus et, venenatis dolor.
  </div>
  <div class="sectionThree">
    Cras eget lectus non dolor congue dapibus in id massa. Nullam porta est accumsan lacinia tempus. Curabitur convallis ex nec vestibulum semper. Vivamus lorem
  </div>


  <div class="sectionOne">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Adipiscing elit.Lorem ipsum
    dolor sit amet, consectetur adipiscing elit.
  </div>
  <div class="sectionTwo">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum, aliquam magna non, vestibulum nibh. Curabitur in eros ornare, ultricies tellus et, venenatis dolor. Curabitur in eros ornare, ultricies tellus et, venenatis dolor.
  </div>
  <div class="sectionThree">
    Cras eget lectus non dolor congue dapibus in id massa. Nullam porta est accumsan lacinia tempus. Curabitur convallis ex nec vestibulum semper. Vivamus lorem
  </div>

</div>

<div class="cols">

  <div class="sectionOne">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </div>
  <div class="sectionTwo">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum.
  </div>
  <div class="sectionThree">
    Cras eget lectus non dolor congue dapibus in id massa. Nullam porta est accumsan lacinia tempus. Curabitur convallis ex nec vestibulum semper. Vivamus lorem
  </div>


  <div class="sectionOne">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </div>
  <div class="sectionTwo">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum, aliquam magna non, vestibulum nibh. Curabitur in eros ornare, ultricies tellus et, venenatis dolor.
  </div>
  <div class="sectionThree">
    Cras eget lectus non dolor congue dapibus in id massa.
  </div>


  <div class="sectionOne">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </div>
  <div class="sectionTwo">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis sem interdum, aliquam magna non, vestibulum nibh. Curabitur in eros ornare, ultricies tellus et, venenatis dolor. Curabitur in eros ornare, ultricies tellus et, venenatis dolor.
  </div>
  <div class="sectionThree">
    Cras eget lectus non dolor congue dapibus in id massa. Nullam porta est accumsan lacinia tempus.
  </div>

</div>

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

编辑:标记为重复的问题显然不会与此重复。

2 个答案:

答案 0 :(得分:9)

可以这样做:

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));

答案 1 :(得分:1)

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

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;
        }
    }
}

示例用法

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; }
    }
}