实例化从 xml 序列化的所有 class 个对象
Instantiate all class objects serialized from xml
我已经将一个 XML 文件反序列化为一个 class,这使我的 soap 请求成为对象。
当我序列化 C# class 时,大多数 classes 对象不会填充输出 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 = "" };
}
对于嵌套在 "envelope" 中的每个项目,我需要创建新对象,否则输出 xml 文件将被该标签清空。
有什么方法可以做一个迭代,做出我需要的吗?
这些是开始信封的片段代码
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; }
}
并继续包含其他 classes
的正文
[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; }
}
您只定义了 类,没有 类 的属性。请参阅下面的代码:
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; }
}
}
你可以使用反射。
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
到你的类,这样你可以检查什么[=28] =]在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 {
.....
test on dotnetfiddle :
https://dotnetfiddle.net/Xm8nEX
我根据您的示例编写了这段代码,并根据我的需要进行了修改
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
我已经将一个 XML 文件反序列化为一个 class,这使我的 soap 请求成为对象。 当我序列化 C# class 时,大多数 classes 对象不会填充输出 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 = "" };
}
对于嵌套在 "envelope" 中的每个项目,我需要创建新对象,否则输出 xml 文件将被该标签清空。
有什么方法可以做一个迭代,做出我需要的吗?
这些是开始信封的片段代码
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; }
}
并继续包含其他 classes
的正文[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; }
}
您只定义了 类,没有 类 的属性。请参阅下面的代码:
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; }
}
}
你可以使用反射。
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
到你的类,这样你可以检查什么[=28] =]在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 {
.....
test on dotnetfiddle : https://dotnetfiddle.net/Xm8nEX
我根据您的示例编写了这段代码,并根据我的需要进行了修改
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