C# 将对象序列化为平面字典<;字符串,字符串>;

C# 将对象序列化为平面字典<;字符串,字符串>;,c#,.net,asp.net-mvc,serialization,C#,.net,Asp.net Mvc,Serialization,上课 public class MyClass { public MyInnerClass Property1 {get;set;} public MyInnerClass2 Field1 public MyInnnerClass[] Property2 {get;set;} } 我需要一个序列化程序,就像MVC序列化程序一样,将上面的内容序列化到下面的字典中 new { { "Property1.InnerField", "1"

上课

public class MyClass
{
    public MyInnerClass Property1 {get;set;}
    public MyInnerClass2 Field1
    public MyInnnerClass[] Property2 {get;set;}
}
我需要一个序列化程序,就像MVC序列化程序一样,将上面的内容序列化到下面的字典中

new {
        {
            "Property1.InnerField", "1",
        },
        {
            "Field1.InnerProperty", "7/7/2007"
        },
        {
            "Property2[0].InnerProperty", "0"
        },
        {
            "Property2[1].InnerProperty", "1"
        }
}

基本上,它需要位置和本机值,或者进一步递归,直到找到一个非引用类型。

谈到您的问题,我们可能会以说教的方式给出答案,而只是排除任何现有的序列化体系结构。这样,您就可以完全自由地进入对象引用树,而无需使用反射和填充结果字典

new {
        {
            "Property1.InnerField", "1",
        },
        {
            "Field1.InnerProperty", "7/7/2007"
        },
        {
            "Property2[0].InnerProperty", "0"
        },
        {
            "Property2[1].InnerProperty", "1"
        }
}
我们需要一个简单的方法来访问给定的对象,然后对每个公共属性递归地调用它自己。签名应该包含一个字符串,表示它是当前父链(例如:
“Property1.InnerProperty4.InnerProperty7”
),返回类型应该是一个
字典
,只包含来自当前和嵌套对象的内容。 在开始时,它应该检查参数是否为值类型,在前一种情况下,只需创建一个新字典,添加一个新的KeyValuePair(parent+name,value)并返回;在后一种情况下,创建一个新字典,然后foreach公共属性调用自身,传递当前属性parent+name字符串,并将返回的字典与先前创建的字典连接起来,并在循环结束时返回这个大字典。我们可以在开始检查传递的对象是否实现了类似IEnumerable接口的东西时添加另一个条件。在这种情况下,不只是循环遍历其成员,而是循环遍历其索引器并为每个项调用方法

我抽出时间来实施我昨天描述的内容。这里有一个递归方法,用于返回给定对象的(公共属性全名)-(值)对字典。当然,它可能并不完全是你想要实现的细节,但你会发现许多技巧、想法和概念,来组成你自己的:

namespace MyNamespace
{
    public class ClassA {
        int p1 = 1;
        string p2 = "abcdef"; 
        List<string> p3 = new List<string>() { "ghi","lmn" };
        ClassB p4 = new ClassB();
        ClassB p5 = null;

        public int PA1 { get { return p1; } }
        public string PA2 { get { return p2; } }
        public List<string> PA3 { get { return p3; } }
        public ClassB PA4 { get { return p4; } }
        public ClassB PA5 { get { return p5; } }
    }

    public class ClassB{
        private string p1 = "zeta";
        public string PB1 { get { return p1; } }
    }

    public class Program {

        public void Main()
        {
            ClassA o = new ClassA();
            Dictionary<string, string> result = GetPropertiesDeepRecursive(o, "[o]", new List<string>() { "MyNamespace" });
        }

        /// <summary>
        /// Returns a dictionary of propertyFullname-value pairs of the given object (and deep recursively for its public properties)
        /// note: it's object oriented (on purpose) and NOT type oriented! so it will just return values of not null object trees
        /// <param name="includedNamespaces">a list of full namespaces for whose types you want to deep search in the tree</param>
        /// </summary>        
        public Dictionary<string, string> GetPropertiesDeepRecursive(object o, string memberChain, List<string> includedNamespaces)
        {

            List<string> types_to_exclude_by_design = new List<string>() { "System.string", "System.String" };

            //the results bag
            Dictionary<string, string> r = new Dictionary<string, string>();

            //if o is null just return value = [null]
            if (o == null)
            {
                r.Add(memberChain, "[null]");
                return r;
            }

            //the current object argument type
            Type type = o.GetType();

            //reserve a special treatment for specific types by design (like string -that's a list of chars and you don't want to iterate on its items)
            if (types_to_exclude_by_design.Contains(type.FullName))
            {
                r.Add(memberChain, o.ToString());
                return r;
            }

            //if the type implements the IEnumerable interface...
            bool isEnumerable =
                type
                .GetInterfaces()
                .Any(t => t == typeof(System.Collections.IEnumerable));
            if (isEnumerable)
            {
                int i_item = 0;
                //loop through the collection using the enumerator strategy and collect all items in the result bag
                //note: if the collection is empty it will not return anything about its existence,
                //      because the method is supposed to catch value items not the list itself                
                foreach (object item in (System.Collections.IEnumerable)o)
                {
                    string itemInnerMember = string.Format("{0}[{1}]", memberChain, i_item++);
                    r = r.Concat(GetPropertiesDeepRecursive(item, itemInnerMember, includedNamespaces)).ToDictionary(e => e.Key, e => e.Value);
                }
                return r;
            }

            //here you need a strategy to exclude types you don't want to inspect deeper like int,string and so on
            //in those cases the method will just return the value using the specific object.ToString() implementation
            //now we are using a condition to include some specific types on deeper inspection and exclude all the rest
            if (!includedNamespaces.Contains(type.Namespace))
            {
                r.Add(memberChain, o.ToString());
                return r;
            }

            //otherwise go deeper in the object tree...            
            //and foreach object public property collect each value
            PropertyInfo[] pList = type.GetProperties();
            foreach (PropertyInfo p in pList)
            {
                object innerObject = p.GetValue(o, null);
                string innerMember = string.Format("{0}.{1}", memberChain, p.Name);
                r = r.Concat(GetPropertiesDeepRecursive(innerObject, innerMember, includedNamespaces)).ToDictionary(e => e.Key, e => e.Value);
            }
            return r;
        }
    }
}
名称空间MyNamespace
{
甲级公共课{
int p1=1;
字符串p2=“abcdef”;
列表p3=新列表(){“ghi”,“lmn”};
ClassB p4=新的ClassB();
b类p5=null;
公共int PA1{get{return p1;}}
公共字符串PA2{get{return p2;}}
公共列表PA3{get{return p3;}}
公共类B PA4{get{return p4;}}
公共类B PA5{get{return p5;}}
}
公共B类{
私有字符串p1=“zeta”;
公共字符串PB1{get{return p1;}}
}
公共课程{
公共图书馆
{
ClassA o=新的ClassA();
Dictionary result=GetPropertiesDeepRecursive(o,[o]”,new List(){“MyNamespace”});
}
/// 
///返回给定对象的propertyFullname值对字典(对于其公共属性,返回递归深度)
///注意:它是面向对象的(故意的),而不是面向类型的!因此它只返回非空对象树的值
///要在树中深入搜索其类型的完整名称空间列表
///         
公共字典GetPropertiesDeepRecursive(对象o、字符串成员链、列表包含名称空间)
{
列表类型通过_design=new List(){“System.string”,“System.string”}排除_;
//结果袋
字典r=新字典();
//如果o为null,则只返回值=[null]
如果(o==null)
{
r、 添加(memberChain,“[null]”;
返回r;
}
//当前对象参数类型
Type Type=o.GetType();
//按设计为特定类型保留特殊处理(如字符串-这是一个字符列表,您不想迭代它的项)
if(类型到排除由设计包含(类型全名))
{
r、 添加(memberChain,o.ToString());
返回r;
}
//如果类型实现IEnumerable接口。。。
布尔可数=
类型
.GetInterfaces()
.Any(t=>t==typeof(System.Collections.IEnumerable));
如果(可计算)
{
int i_项=0;
//使用枚举器策略循环收集,并收集结果包中的所有项目
//注意:如果集合为空,则不会返回关于其存在的任何信息,
//因为该方法应该捕获值项,而不是列表本身
foreach(在(System.Collections.IEnumerable)o中的对象项)
{
string iteminermember=string.Format(“{0}[{1}]”,memberChain,i_item++);
r=r.Concat(GetPropertiesDeepRecursive(item,itemInnerMember,includedNamespaces)).ToDictionary(e=>e.Key,e=>e.Value);
}
返回r;
}
//在这里,您需要一种策略来排除不希望深入检查的类型,如int、string等
//在这些情况下,该方法将仅使用特定的object.ToString()实现返回值
//现在我们使用一个条件来包含一些特定类型的深入检查,并排除所有其他类型
如果(!includeNamespaces.Contains(type.Namespace))
{
r、 添加(memberChain,o.ToString());
返回r;
}
//否则,请在对象树中深入查看。。。
//和foreach对象公共属性收集每个值
PropertyInfo[]pList=type.GetProperties();
foreach(pList中p的属性)
{
对象innerObject=p.GetValue(o,null);
字符串innerMember=string.Format(“{0}.{1}”,memberChain,p.Name);
r=r.Concat(GetPropertiesDeepRecu