【问题标题】:Instantiate all class objects serialized from xml实例化从 xml 序列化的所有类对象
【发布时间】:2020-02-10 18:31:07
【问题描述】:

我已将一个 XML 文件反序列化为一个类,该类使我的肥皂请求对象。 当我序列化 C# 类时,大多数类对象都不会填充输出 xml 文件。

例子

GetUserReq.Envelope getUser = new GetUserReq.Envelope();
getUserResponse = new GetUserRes.Envelope();
getUser.Body = new GetUserReq.Body();
getUser.Body.GetUser = new GetUserReq.GetUser();
getUser.Body.GetUser.ReturnedTags = new GetUserReq.ReturnedTags();

if (allReturnTags)
{
    getUser.Body.GetUser.ReturnedTags.AssociatedGroups = new GetUserReq.AssociatedGroups();
    getUser.Body.GetUser.ReturnedTags.AssociatedDevices = new GetUserReq.AssociatedDevices();
    getUser.Body.GetUser.ReturnedTags.AssociatedGroups.UserGroup = new GetUserReq.UserGroup() { Name = "", UserRoles = new GetUserReq.UserRoles() };
    getUser.Body.GetUser.ReturnedTags.AssociatedGroups.UserGroup.UserRoles = new GetUserReq.UserRoles() { UserRole = "" };
}

对于嵌套在“信封”中的每个项目,我需要创建新对象,否则输出 xml 文件将被该标记为空。

有什么方法可以进行迭代并做出我需要的东西?

这是一个sn-p代码,其中开始信封

public class GetUserReq {
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public class Envelope
        {
            [XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
            public string Header { get; set; }
            [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
            public Body Body { get; set; }
            [XmlAttribute(AttributeName = "soapenv", Namespace = "http://www.w3.org/2000/xmlns/")]
            public string Soapenv { get; set; }
            [XmlAttribute(AttributeName = "ns", Namespace = "http://www.w3.org/2000/xmlns/")]
            public string Ns { get; set; }
        }

然后继续处理包含其他类的主体

[XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Body
    {
        [XmlElement(ElementName = "getUser", Namespace = "http://www.cisco.com/AXL/API/9.1")]
        public GetUser GetUser { get; set; }
    }

【问题讨论】:

  • Envelope 是自定义类吗?还是来自某些第三方库?如果这些类是自定义的,您应该将它们添加到您的问题中
  • 没有信封是我的 xml 的根元素,它包含另一个..
  • 你有没有尝试在构造函数上初始化这些子类?
  • 是的,我可以,但我正在寻找解决方案,因为我有很多文件和很多类,它们的属性嵌套在列表或其他类型的对象中。

标签: c# xml xml-serialization


【解决方案1】:

你可以使用反射。


public object CascadeInitializer(Type type)     
{
    var newObj = Activator.CreateInstance(type); // create new instance of your target class
    Func<PropertyInfo,bool> query = q
        => q.PropertyType.IsClass &&            // Check if property is a class
           q.CanWrite &&                        // Check if property is not readOnly
           q.PropertyType != typeof(string);    // Check if property is not string

    foreach (var el in type.GetProperties().Where(query))
    {
        // create new instance of el cascade
        var elInstance = CascadeInitializer(el.PropertyType);
        el.SetValue(newObj, elInstance);
    }
    return newObj;
}

// a generic overload to easier usage
public T CascadeInitializer<T>() => (T)CascadeInitializer(typeof(T));

用法

var x =  CascadeInitializer<Envelope>();

如果你想控制哪些类应该被自动初始化,你可以在你的类中添加一个空接口interface IInitializable,这样你就可以在Func query中检查IInitializable类型的属性是什么。

例如

Func<PropertyInfo,bool> query = q
    => q.PropertyType.IsClass &&            // Check if property is a class
       q.CanWrite &&                        // Check if property is not readOnly
       q.PropertyType != typeof(string) &&  // Check if property is not string
       q.PropertyType.GetInterfaces()       // Check what classes should be initialize 
           .Any(i => i.Name == nameof(IInitializable) );

...
public interface IInitializable{}

public class Envelope : IInitializable {
.....


在 dotnetfiddle 上进行测试: https://dotnetfiddle.net/Xm8nEX

【讨论】:

  • 很抱歉,我有 13 名声望我不能...
  • 现在我在列表类型参数计数不匹配时遇到错误。我尝试使用此命令 el.SetValue(newObj, elInstance,new object[]{0});但响应是索引超出范围。必须是非负数且小于集合的大小。 (参数“索引”)
  • 您可以根据需要忽略列表类型(只需为列表添加另一个 if 条件)或像这样初始化列表:stackoverflow.com/a/38329808/786376
【解决方案2】:

您只是定义类,并没有类的属性。请参阅下面的代码:

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            GetUserReq userReq = new GetUserReq();
            userReq.Envelope = new Envelope();
            GetUserResponse userResponse = new GetUserResponse();
            userResponse.Envelope = new Envelope();
            userReq.Body = new Body();
            userReq.Body.GetUser = new GetUser();
            userReq.Body.GetUser.ReturnedTags = new ReturnedTags();

            Boolean allReturnTags = true;
            if (allReturnTags)
            {
                userReq.Body.GetUser.ReturnedTags.AssociatedGroups = new AssociatedGroups();
                userReq.Body.GetUser.ReturnedTags.AssociatedDevices = new AssociatedDevices();
                userReq.Body.GetUser.ReturnedTags.AssociatedGroups.UserGroup = new UserGroup() { Name = "", UserRoles = new UserRoles() };
                userReq.Body.GetUser.ReturnedTags.AssociatedGroups.UserGroup.UserRoles = new UserRoles() { UserRole = "" };
            }

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create(FILENAME, settings);

            XmlSerializer serializer = new XmlSerializer(typeof(GetUserReq));
            serializer.Serialize(writer, userReq);
        }
    }
    [XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Body
    {
        [XmlElement(ElementName = "getUser", Namespace = "http://www.cisco.com/AXL/API/9.1")]
        public GetUser GetUser { get; set; }
    }
    public class GetUser
    {
        public ReturnedTags ReturnedTags { get; set; }
    }
    public class ReturnedTags
    {
        public AssociatedGroups AssociatedGroups { get; set; }
        public AssociatedDevices AssociatedDevices { get; set; }
    }
    public class GetUserReq
    {
        public Envelope Envelope { get; set; }
        public Body Body { get; set; }

    }
    public class GetUserResponse
    {
        public Envelope Envelope { get; set; }

    }
    [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Envelope
    {
        [XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public string Header { get; set; }
        [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public Body Body { get; set; }
        [XmlAttribute(AttributeName = "soapenv", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Soapenv { get; set; }
        [XmlAttribute(AttributeName = "ns", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Ns { get; set; }
    }
    public class AssociatedGroups
    {
        public UserGroup UserGroup { get; set; }
    }
    public class AssociatedDevices
    {
    }
    public class UserGroup
    {
        public UserRoles UserRoles { get; set; }
        public string Name { get; set; }
    }
    public class UserRoles
    {
        public string UserRole { get; set; }
    }
}

【讨论】:

  • 嗨,问题不是属性,上面的代码是序列化xml的整个代码的sn-p。我的问题是我是否可以使用 foreach 循环实例化信封等的所有属性。谢谢你
  • 数据的来源是什么? xml 的输出是什么样的?我通常在做动态实例化的时候使用其他的方法来生成xml。例如,使用 xml linq 您可以使用以下方法生成新元素: XElement newNode = new XElement("Name", "Value");其中名称和值是字符串。
【解决方案3】:

我根据您的示例编写了这段代码,并根据我的需要进行了修改

    public T AllReturnTags<T>() => (T)AllReturnTags(typeof(T));

    public object AllReturnTags(Type type)
    {
        var newObj = Activator.CreateInstance(type); // create new instance of your target class

        Func<PropertyInfo, bool> query = q
             => q.PropertyType.IsClass &&         
                q.CanWrite;                  

        foreach (var el in type.GetProperties().Where(query))
        {
            // create new instance of el cascade
            if (el.PropertyType == typeof(string))
            {
                el.SetValue(newObj, "", null);
            }
            if (el.PropertyType == typeof(Int32))
            {
                el.SetValue(newObj, 0, null);
            }
            if (el.PropertyType.IsClass && el.PropertyType != typeof(string) && el.PropertyType != typeof(Int32) && el.PropertyType.IsGenericType == true && el.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
            {
                var elInstance = AllReturnTags(el.PropertyType);
                Type itemType = typeof(List<>).MakeGenericType(elInstance.GetType());
                IList res = (IList)Activator.CreateInstance(itemType);
                res.Add(elInstance);
                try { el.SetValue(newObj, res, null); } catch {  };
            }
            if (el.PropertyType.IsClass && el.PropertyType != typeof(string) && el.PropertyType != typeof(Int32) && el.PropertyType.IsGenericType != true )
            {
                var elInstance = AllReturnTags(el.PropertyType);
                try { el.SetValue(newObj, elInstance, null); } catch { return elInstance; };
            }

        }
        return newObj;
    }

这似乎适用于单个项目和列表。 谢谢你@AliReza

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 2013-09-24
    相关资源
    最近更新 更多