我如何找到一个对象使用的所有类型;s成员递归

本文关键字:类型 递归 成员 何找 一个对象 | 更新日期: 2023-09-27 17:58:39

我正在尝试使用DataContractJsonSerializer来序列化和反序列化包含不同类型的对象[]的c#对象。

我需要找到XmlRequest使用的所有类型及其对象[]中的对象,这样我就可以将类型列表传递给DataContractJsonSerializer。

XmlRequest中的对象[]将包含不同的类型。TypeX,TypeY,字符串,int,TypeZ

var sr = new DataContractJsonSerializer(typeof(XmlRequest), knownTypes);

Xml请求类:

[DataContract]
    public class XmlRequest
    {
        [DataMember]
        public object[] Parameters { get; set; }
        [DataMember]
        public string Name { get; set; }
    }

我如何找到一个对象使用的所有类型;s成员递归

我看到了问题的答案,正如所写的,但我想进一步探索。

您是否试图对XmlRequest进行泛型,以便它可以接受一个或多个单一类型的对象,如:

Object[] ary = new Object[] { new MyObject(), new MyObject() };

或者你真的在一个数组中抛出了多个类型,如:

Object[] ary = new Object[] { new MyObject(), new MyOtherObject() };

如果您正在执行前者,请考虑使用泛型。对于Request,这不是最异构的解决方案,但XmlRequest是加载对象、单个类型的数组等的绝佳方法。

如果您使用前者并使用泛型,序列化会更容易,并且不需要更重的"检查每个类型"方法,因为Parameters数组是强类型的。

public void CollectTypes(Type type, HashSet<Type> types)
{
    if (types.Contains(type)) return;
    types.Add(type);
    foreach (FieldInfo fi in type.GetFields(BindingFlags.Instance | BindingFlags.Public))
    {
        if (!fi.IsInitOnly)
        {
            CollectTypes(fi.FieldType, types);
        }
    }
    foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
    {
        if (pi.CanWrite && pi.CanRead)
        {
            CollectTypes(pi.PropertyType, types);
        }
    }
}

用法:

object[] parameters = ....;
HashSet<Type> types = new HashSet<Type>();
foreach(object p in parameters)
{
    if (p != null)
    {
      CollectTypes(p.GetType(), types)
    }
}
var sr = new DataContractJsonSerializer(typeof(XmlRequest), types.ToArray());

如果反序列化程序能够写入只读成员,则不需要检查给定成员是否为只读。

我通过配置找到了如何做到这一点,而不是试图在运行时发现这些项。

<system.runtime.serialization>
        <dataContractSerializer>
            <declaredTypes>
                <add type="Whatever.XmlRequest, Whatever, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
                    <knownType type="WhateverLibary.Parameter, WhateverLibary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
                </add>
            </declaredTypes>
        </dataContractSerializer>
    </system.runtime.serialization>