I am using Linq-to-Xml to read XML and update an existing data structure. Right now I have the following code to do this:
// Load all the test plan details
var details = doc.Descendants()
.Select(x => new
{
Name = x.Attribute("name").ToStringValue(),
DbName = x.Attribute(DATABASE_ATTR).ToStringValue(),
Login = x.Attribute(USERNAME_ATTR).ToStringValue(),
Password = x.Attribute(PASSWORD_ATTR).ToStringValue(),
AppSource = x.Attribute(APPSOURCE_ATTR).ToStringValue()
})
.First();
testPlan.Name = details.Name;
testPlan.DatabaseName = details.DbName;
testPlan.LoginUsername = details.Login;
testPlan.LoginPassword = details.Password;
testPlan.ApplicationSource = details.AppSource;
}
This is kind of annoying to me because I have to create a temp variable and perform the data transfer. Is there any way for me to update the testPlan
variable straight from within the Linq statement, which would cut down one step? I could not get it to work by adding the update code into the .Select()
statement.
The following should work:
doc.Descendants().First()
.Select(x =>
{
testPlan.Name= x.Attribute("name").ToStringValue();
testPlan.DatabaseName = x.Attribute(DATABASE_ATTR)
.ToStringValue();
testPlan.LoginUsername = x.Attribute(USERNAME_ATTR)
.ToStringValue();
testPlan.LoginPassword = x.Attribute(PASSWORD_ATTR)
.ToStringValue();
testPlan.ApplicationSource = x.Attribute(APPSOURCE_ATTR)
.ToStringValue();
return testPlan;
})
.ToList();
The call to First
in the middle is to ensure, that only the attributes of the first descendant will be assigned to the properties of testPlan
. The ToList
at the end is used to really execute the code inside Select
.
Although this works, I don't recommend using it, because it uses LINQ in a way it wasn't created for. Furthermore, it's easy to create it wrong:
First
, testPlan will contain the attribute values of the last element in your XML, because the select code is executed for each element and overwrites the properties. ToList
or a similar method that forces the execution, the code inside Select
will never be executed. So, basically, the problem is, that you create a lot of possibilities to introduce a bug.
I would implement something like this in the following way:
var x = doc.Descendants.First();
testPlan.Name= x.Attribute("name").ToStringValue();
testPlan.DatabaseName = x.Attribute(DATABASE_ATTR).ToStringValue();
testPlan.LoginUsername = x.Attribute(USERNAME_ATTR).ToStringValue();
testPlan.LoginPassword = x.Attribute(PASSWORD_ATTR).ToStringValue();
testPlan.ApplicationSource = x.Attribute(APPSOURCE_ATTR).ToStringValue();
This is shorter, easier to read and doesn't violate LINQ to do something it wasn't created for.
What I would do is create a constructor in the TestPlan class that takes a argument of type details?
Then just call testPlan = new TestPlan(details);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.