是否可以使用LINQ初始化类构造函数中的对象?

时间:2010-11-18 06:46:08

标签: c# linq oop constructor

我是不是想错了?还是遗漏了一些完全明显我可以通过例子最好地展示。这段代码就是我现在初始化一个新对象的方法。这似乎是多余的。

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();
    }
}

我觉得应该有办法完成我想要做的事情。我必须错过一些语法或fundemetal理解为什么它没有。或者也许我只是疯了以为它应该这样做。

4 个答案:

答案 0 :(得分:1)

你需要使它成为一个静态方法并创建一个新的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();

    }

答案 1 :(得分: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 :(得分:0)

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

答案 3 :(得分:0)

永远不要在构造函数中写“危险代码”。您尝试加载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
}