【问题标题】:Is it possible to initialize an object in a class constructor using LINQ?是否可以使用 LINQ 在类构造函数中初始化对象?
【发布时间】:2010-11-18 06:46:07
【问题描述】:

我是不是想错了?或者遗漏了一些完全明显的东西?我最好举个例子。这段代码是我现在初始化一个新对象的方式。这似乎是多余的。

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public Person(int Id)
    {
        XDocument personXml = XDocument.Load("person.xml");
        var person = (from p in personXml.Descendants("Person")
                      where (int)p.Attribute("id") == Id
                      select new
                      {
                          FirstName = (string)p.Element("FirstName"),
                          LastName = (string)p.Element("LastName"),
                          Age = (int)p.Element("Age")
                      }).SingleOrDefault();

        //with the "select new" in query I have to set the properties manually
        FirstName = person.FirstName;
        LastName = person.LastName;
        Age = person.Age;
    }
}

这就是我正在尝试做的,但无法让它发挥作用:

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public Person(int Id)
    {
        XDocument personXml = XDocument.Load("person.xml");
        (from p in personXml.Descendants("Person")
         where (int)p.Attribute("id") == Id
         select
         {
             FirstName = (string)p.Element("FirstName"),
             LastName = (string)p.Element("LastName"),
             Age = (int)p.Element("Age")
         }).SingleOrDefault();
    }
}

我觉得应该有一种方法来完成我正在尝试做的事情。我一定错过了一些句法或基本的理解,为什么它没有。或者也许我只是疯狂地认为应该这样做。

【问题讨论】:

    标签: c# linq oop constructor


    【解决方案1】:

    这不是 LINQ 的目的。你所拥有的是一个查询投影,它可能有数百行来自它。在那里设置查询外部的值是没有意义的,因为只有最后一个会保留。

    但是,您可以这样做:

    public static Person CreatePerson(int Id)
    {
        return (from p in XDocument.Load("person.xml").Descendants("Person")
                where (int)p.Attribute("id") == Id
                select new Person
                       {
                           FirstName = (string)p.Element("FirstName"),
                           LastName = (string)p.Element("LastName"),
                           Age = (int)p.Element("Age")
                       }).SingleOrDefault();
    }
    

    进一步的重要说明: 一般来说,在构造函数中进行 I/O 和其他昂贵(并且可能容易出错)的工作是一个坏主意。您通常可以通过缩短构造函数并在像这样的工厂方法中加载数据来避免问题。

    【讨论】:

    • 我开始走这条路,并正在探索其他途径,正如我上面的问题所证明的那样。这是我将在我的课程中实现的模式。谢谢。
    【解决方案2】:

    您需要将其设为静态方法并创建一个新的 Person 对象,如下所示:

        public static Person LoadPerson (int Id)
        {
            XDocument personXml = XDocument.Load("person.xml");
            var person = (from p in personXml.Descendants("Person")
                          where (int)p.Attribute("id") == Id
                          select new Person
                          {
                              FirstName = (string)p.Element("FirstName"),
                              LastName = (string)p.Element("LastName"),
                              Age = (int)p.Element("Age")
                          }).SingleOrDefault();
    
        }
    

    【讨论】:

    • 您缺少返回类型。
    • 谢谢,或者方法名:)
    【解决方案3】:

    切勿在构造函数中编写“危险代码”。您尝试加载 XML 以在构造函数中构建实例的行为被认为是“危险的”,因为代码可能会引发异常(即使添加了 try-catch 块也不建议这样做)。看来你想实现Factory Pattern。所以你需要一个PersonManager,它就像一个工厂,用静态方法为其他人生产Person实例。

    public class PersonManager
    {
       public static Person GetPerson(int id)
       {
          //get the Person here
       }
    }
    

    你的Person 类应该很简单:

    public class Person
    {
       //others can only get Person instances from your PersonManager
       internal Person() { }   
    
       public string FristName { get; set; }
       public string LastName { get; set; }
    
       // and some other properties/methods which are really related to a Person
    }
    

    【讨论】:

      【解决方案4】:

      您的第一个版本是正确的,没有多余的。当您调用 Select(new...) 时,您会创建匿名类型,而不是初始化您的...而且它也是惰性的 - 匿名类型属性在您实际使用它们之前不会被初始化。

      【讨论】:

      • 第二个版本不仅不能编译,而且无论如何都不是一个好主意——在投影的周围环境中设置实例变量对我来说听起来是个坏主意。
      猜你喜欢
      • 2021-11-06
      • 2017-07-20
      • 1970-01-01
      • 2015-11-05
      • 2020-12-11
      • 1970-01-01
      • 1970-01-01
      • 2013-12-30
      • 1970-01-01
      相关资源
      最近更新 更多