Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Linq,如何将Xml解析为只接受构造函数中参数的C对象?_C#_Xml_Linq - Fatal编程技术网

C# 使用Linq,如何将Xml解析为只接受构造函数中参数的C对象?

C# 使用Linq,如何将Xml解析为只接受构造函数中参数的C对象?,c#,xml,linq,C#,Xml,Linq,假设我有这样一些XML: <User> <Name>X</Name> <Gender>Y</Gender> <ImageUrl>Z</ImageUrl> </User> 它只接受构造函数公共用户名、字符串性别、字符串ImageUrl,不允许设置属性,使用linq和c将xml解析为这些对象的最佳方法是什么 以一种粗略的方式,可以创建匿名对象,然后对其进行迭代以创建所需的对象。有

假设我有这样一些XML:

<User>
    <Name>X</Name>
    <Gender>Y</Gender>
    <ImageUrl>Z</ImageUrl>
</User>
它只接受构造函数公共用户名、字符串性别、字符串ImageUrl,不允许设置属性,使用linq和c将xml解析为这些对象的最佳方法是什么


以一种粗略的方式,可以创建匿名对象,然后对其进行迭代以创建所需的对象。有更有效的方法吗?

您根本不需要任何匿名对象。使用,您只需从XML中选择用户节点,并通过使用从XML节点中选择的值调用构造函数来创建实际的用户类实例:

// xml contains XML string, like in your sample
var document = XDocument.Parse(xml);
var users = document.Descendants("User")
   .Select(u => new User(
       u.Element("Name").Value,
       u.Element("Gender").Value, 
       u.Element("ImageUrl").Value
   ));

如果您想要一个对大多数类都可重用的方法,下面是我过去使用过的一些方法

请记住,这使用了反射,所以它的速度不如jimmy_keen的答案快。既然你提到了“高效”,这就不会像他的回答那么快了——不管它值多少钱:

代码如下:

    ConstructorInfo GetBestConstructor(XElement elm, Type itemType)
    {
        var elements = elm.Elements();

        // Get a constructor with the most parameters that
        // are provided by xml elements.
        var ctor = (
            from c in itemType.GetConstructors()
            let p = c.GetParameters()
            where
                p.Length > 0 &&
                p.Count(parm => elements.Any(e => e.Name.LocalName.Equals(parm.Name, StringComparison.InvariantCultureIgnoreCase))) == p.Length
            select c
        )
            // Put the constructor with the most matching parameters
            // at the top of the list
        .OrderByDescending(c => c.GetParameters().Length)
        .FirstOrDefault();

        return ctor;
    }

    TType Construct<TType>(XElement elm)
    {
        var ctor = GetBestConstructor(elm, typeof(TType));
        if (ctor != null)
        {
            // We found a valid contructor!
            List<object> parameters = new List<object>();

            // Build a list of parameters, deserializing as we go.
            foreach (var p in ctor.GetParameters())
            {
                var item = elm.Elements().FirstOrDefault(e => e.Name.LocalName.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase));
                if (item != null)
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(p.ParameterType);
                    if (converter != null &&
                        converter.CanConvertFrom(typeof(string)))
                    {
                        // Deserialize each parameter and add it.
                        var parameter = converter.ConvertFrom(item.Value);
                        parameters.Add(parameter);
                    }
                }
            }

            // Create the object, using each parameter we've deserialized
            // to pass to the constructor.
            return (TType)ctor.Invoke(parameters.ToArray());
        }
        return default(TType);
    }

    public class User
    {
        public User(string name, string gender, string imageUrl)
        {
            Name = name;
            Gender = gender;
            ImageUrl = imageUrl;
        }
        public string Name { get; protected set; }
        public string Gender { get; protected set; }
        public string ImageUrl { get; protected set; }
    }

    public IEnumerable<User> GetUsers()
    {
        XDocument doc = XDocument.Parse(@"
<User>
    <Name>X</Name>
    <Gender>Y</Gender>
    <ImageUrl>Z</ImageUrl>
</User>");

        return doc
            .Descendants("User")
            .Select(u => Construct<User>(u));
    }

    static public void Main()
    {
        var p = new Program();
        var users = p.GetUsers().ToArray();
    }
对你的需求来说可能是过度了,但我想我还是把它扔出去吧

-道格

    ConstructorInfo GetBestConstructor(XElement elm, Type itemType)
    {
        var elements = elm.Elements();

        // Get a constructor with the most parameters that
        // are provided by xml elements.
        var ctor = (
            from c in itemType.GetConstructors()
            let p = c.GetParameters()
            where
                p.Length > 0 &&
                p.Count(parm => elements.Any(e => e.Name.LocalName.Equals(parm.Name, StringComparison.InvariantCultureIgnoreCase))) == p.Length
            select c
        )
            // Put the constructor with the most matching parameters
            // at the top of the list
        .OrderByDescending(c => c.GetParameters().Length)
        .FirstOrDefault();

        return ctor;
    }

    TType Construct<TType>(XElement elm)
    {
        var ctor = GetBestConstructor(elm, typeof(TType));
        if (ctor != null)
        {
            // We found a valid contructor!
            List<object> parameters = new List<object>();

            // Build a list of parameters, deserializing as we go.
            foreach (var p in ctor.GetParameters())
            {
                var item = elm.Elements().FirstOrDefault(e => e.Name.LocalName.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase));
                if (item != null)
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(p.ParameterType);
                    if (converter != null &&
                        converter.CanConvertFrom(typeof(string)))
                    {
                        // Deserialize each parameter and add it.
                        var parameter = converter.ConvertFrom(item.Value);
                        parameters.Add(parameter);
                    }
                }
            }

            // Create the object, using each parameter we've deserialized
            // to pass to the constructor.
            return (TType)ctor.Invoke(parameters.ToArray());
        }
        return default(TType);
    }

    public class User
    {
        public User(string name, string gender, string imageUrl)
        {
            Name = name;
            Gender = gender;
            ImageUrl = imageUrl;
        }
        public string Name { get; protected set; }
        public string Gender { get; protected set; }
        public string ImageUrl { get; protected set; }
    }

    public IEnumerable<User> GetUsers()
    {
        XDocument doc = XDocument.Parse(@"
<User>
    <Name>X</Name>
    <Gender>Y</Gender>
    <ImageUrl>Z</ImageUrl>
</User>");

        return doc
            .Descendants("User")
            .Select(u => Construct<User>(u));
    }

    static public void Main()
    {
        var p = new Program();
        var users = p.GetUsers().ToArray();
    }