return a class directly from a linq query
I'm still new to LINQ. Is it possible to do the following:
e.g., I have a class:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Now i want to return it as a class object by reading, say, an xml file's contents and returning it.
So if i read this xml file:
<person>
<firstname></firstname>
<lastname></lastname>
</person>
Read Person (say this belongs to a People class):
public static Person ReadPerson(xmlpath)
{
XDocument xd = XDocument.Load(xmlpath);
var person = (from p in xd.Descendants("person")
select new Person
{
FirstName = p.Element("firstname").value,
LastName = p.Element("lastname").value
});
return person as Person;
}
Now if i do the following elsewhere:
Person p = new Person();
p = People.Person(xmlpath);
Response.Write(p.FirstNam开发者_高级运维e);
Here, p.FirstName returns a null exception. Which i understand is because the linq query returned an empty class.
So my question is, is there anyway to directly add stuff into a class within a query and return it WITHOUT running a foreach loop and adding everything in manually? (like the following:)
Person p = new Person();
foreach (var x in person)
{
p.FirstName = x.FirstName;
p.LastName = x.LastName;
}
Sorry if this is a stupid question.
Thanks
You need to distinguish between reading a sequence of items and reading a single item. Currently the person
variable in ReadPerson
is actually of type IEnumerable<Person>
- you're returning person as Person
which will be null, because that sequence isn't actually an instance of Person
. If you'd used a cast instead of as
, you'd have seen that earlier - but the very fact that you had to do anything to the types should be a warning that you weren't quite doing the right thing.
I suspect you actually want either this:
public static IEnumerable<Person> ReadPeople(xmlpath)
{
XDocument xd = XDocument.Load(xmlpath);
return from p in xd.Descendants("person")
select new Person
{
FirstName = p.Element("firstname").value,
LastName = p.Element("lastname").value
});
}
or this:
public static Person ReadPerson(xmlpath)
{
XDocument xd = XDocument.Load(xmlpath);
XElement element = xd.Descendants("person").First();
return new Person
{
FirstName = element.Element("firstname").value,
LastName = element.Element("lastname").value
});
}
You should also consider what you want to happen if there are no person
elements, or multiple person elements. The First
, FirstOrDefault
, Single
and SingleOrDefault
methods will be useful for you here.
From how I read it, all you need is:
public static IEnumerable<Person> ReadPeople(xmlpath)
{
XDocument xd = XDocument.Load(xmlpath);
return (from p in xd.Descendants("person")
select new Person
{
FirstName = (string)p.Element("firstname"),
LastName = (string)p.Element("lastname")
});
}
This addresses:
- the issue of returning multiple descendants
- the issue of firstname/lastname not being specified
if you intent there to only be one, then use Single()
/ First()
/ SingleOrDefault()
/ FirstOrDefault()
.
I see the problem! person
in ReadPerson method is not instance of Person
class, but collection (IEnumerable<Person>
) and casting to Person
returns null
.
The following line has the invalid casting problem. You should let the compiler to help you (see my modified function).
return person as Person;
You should return a list of persons instead of just a single person. If you are sure that only one person is in the xml, you can call Single() instead of ToList().
public static List<Person> ReadPerson(xmlpath)
{
XDocument xd = XDocument.Load(xmlpath);
/*var person = (from p in xd.Descendants("person")
select new Person
{
FirstName = p.Element("firstname").value,
LastName = p.Element("lastname").value
});*/
List<Person> persons = (from p in xd.Descendants("person")
select new Person
{
FirstName = p.Element("firstname").value,
LastName = p.Element("lastname").value
}).ToList();
return persons;
}
精彩评论