I have a code that returns me an object of widgets
XDocument loaded = XDocument.Parse( xml );
var widgets = from x in loaded.Descendants( "widget" )
select new
{
URL = x.Descendants( "url" ).First().Value,
Category = x.Descendants( "PortalCategoryId" ).First().Value
};
I am trying to create a method that will return the object widgets and then I need another method where I can cal it from and access the values. I am new to C# and using vs2010
thanks
Anonymous types cannot easily be shared across methods.
You should make a class to store that data.
Instead of
XDocument loaded = XDocument.Parse( xml );
var widgets = from x in loaded.Descendants("widget")
select new // Dynamic/Anonymous class
{
URL = x.Descendants( "url" ).First().Value,
Category = x.Descendants( "PortalCategoryId" ).First().Value
};
It would be better to create a concreate class
//Widget.cs
Public class Widget
{
public string URL { get; set; }
public string Category { get; set; }
}
//Code somewhere else..
XDocument loaded = XDocument.Parse(xml);
IEnumerable<Widget> widgets =
from x in loaded.Descendants("widget")
select new Widget()
{
URL = x.Descendants( "url" ).First().Value,
Category = x.Descendants( "PortalCategoryId" ).First().Value
};
change var widgets to dynamic widgets
example
using System;
using System.Linq;
class Sample {
static object junk(){
var widgets = new { URL = new Uri("http://test.com/"), Category = "address" };
return widgets;
}
static void Main(){
dynamic widgets = junk();//var widgets = .. //NG
Console.WriteLine(widgets.URL);
}
}
Related
Hi I have the following code when I am adding values to a list.
var NoLiftingList = new List<SQLFields>();
SQLFields nolifting = new SQLFields();
nolifting.Field1 = "No lifting";
NoLiftingList.Add(nolifting);
SQLFields extremelifting = new SQLFields();
extremelifting.Field1 = "Up to 100 lbs (extreme lifting)";
NoLiftingList.Add(extremelifting);
How can I simplify this? Instead of initializing a new object all the time.
This is the code for the whole class updated below.
Thanks
You can add to a list, and set properties on a class by using this inline constructor syntax (working example):
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var NoLiftingList = new List<SQLFields>
{
new SQLFields
{
Field1 = "No Lifting"
},
new SQLFields
{
Field1 = "Up to 100lbs (extreme lifting)"
}
};
}
}
public class SQLFields
{
public string Field1 { get; set; }
}
Use Object Initializers with anonymous types
var NoLiftingList = new List<SQLFields>(){
new SQLFields() { Field1 = "No lifting"},
new SQLFields() { Field1 = "Up to 100 lbs (extreme lifting)"}
};
Ref: MSDN Link
Try this
var NoLiftingList = new List<SQLFields>()
{
new SQLFields()
{
Field1 = "No lifting"
},
new SQLFields()
{
Field1 = "Up to 100 lbs (extreme lifting)"
}
};
I received some help here with the following LINQ query, but am still struggling with it. The result I'm trying to obtain is to display some attributes and their values from an xml file in a DataGridView control. I'm calling my method from a button click and am trying to pass back the list for display in the grid. Here is an example of the row:
<z:row CenterCode="JAX" CenterName="Jacksonville" Version="1.0" NextExport="66742" NextImport="29756" LastImportTime="2015-06-10T14:48:33" FtpProxyServer="" FtpUserName="" FtpPassword="" ResetImportID="False"/>
Here is the method:
public static List<string[]> MonitorCounts(string upperLimit)
{
// Load xml
XDocument xmldoc = XDocument.Load(#"c:\XML\Configuration.xml");
XNamespace z = "#RowsetSchema";
Int32 limit = Convert.ToInt32(upperLimit);
var elementQuery = xmldoc.Descendants(z + "row").Where(e => (long?)e.Attribute("NextExport") > limit | (long?)e.Attribute("NextImport") > limit);
var attributes = elementQuery.Select(e => e.Attributes().Select(a => new KeyValuePair<string, string>(a.Name.LocalName, (string)a)).ToList()).ToList();
return attributes;
}
My questions are how to select only specific attributes and values in attributes. If I do something like this:
var attributes = elementQuery.Select(e => e.Attributes("CenterName").Select(a => new KeyValuePair<string, string>(a.Name.LocalName, (string)a)).ToList()).ToList();
then this is returned:
[0] = {[CenterName, Jacksonville]}
I need to select this and 4 others. I'm also getting a convrsion error - Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string,string>>>' to 'System.Collections.Generic.List<string[]>. Appreciate any pointers to help me along.
You can use an anonymous type:
var attributes =
elementQuery.Select(e => new
{
CenterName = (string)e.Attribute["CenterName"],
Version = (string)e.Attribute["Version"],
// more attributes
}).ToList();
You can't however return this from the method in a useful way. So if you really need both the attribute name and the attribute value as strings, try this approach instead:
var attributes =
elementQuery.Select(e => new []
{
Tuple.Create("CenterName", (string)e.Attribute["CenterName"]),
Tuple.Create("Version", (string)e.Attribute["Version"]),
// more attributes
}).SelectMany(x => x).ToList();
The return type of your method now has to be List<Tuple<string, string>>.
And finally, if you actually need a List<string[]> as the return type, use this code:
var attributes =
elementQuery.Select(e => new []
{
new [] { "CenterName", (string)e.Attribute["CenterName"] },
new [] { "Version", (string)e.Attribute["Version"] },
// more attributes
}).SelectMany(x => x).ToList();
I solved my own problem. Here is what I did:
Created a class for the attributes needed:
public class dataRow
{
public string CenterName { get; set; }
public string CenterCode { get; set; }
public string NextImport { get; set; }
public string NextExport { get; set; }
public string LastImportTime { get; set; }
}
Selected the results into it:
List<dataRow> dataRows = elementQuery.Select( e => new dataRow
{ CenterName = (string)e.Attribute("CenterName"),
CenterCode = (string)e.Attribute("CenterCode"),
NextImport = (string)e.Attribute("NextImport"),
NextExport = (string)e.Attribute("NextExport"),
LastImportTime = (string)e.Attribute("LastImportTime") }).ToList();
Changed my method to return the correct object:
public static List<dataRow> MonitorCounts(string upperLimit)
Set my grids datasource to the method return:
dataGridView1.DataSource = xmlProcessing.MonitorCounts(tbxUpperLimit.Text.ToString());
return dataRows;
I have an Interface [BindControls] which takes data from GUI and store it into a list „ieis”.
After that, Into another class, which sends this data through WebServices, I want to take this data from „ieis” and put it into required by WS Class fields (bottom is a snippet of code)
This is the interface:
void BindControls(ValidationFrameBindModel<A.B> model)
{
model.Bind(this.mtbxTax, (obj, value) =>
{
var taxa = TConvertor.Convert<double>((string)value, -1);
if (taxa > 0)
{
var ieis = new List<X>();
var iei = new X
{
service = new ServiceInfo
{
id = Constants.SERVICE_TAX
},
amount = tax,
currency = new CurrencyInfo
{
id = Constants.DEFAULT_CURRENCY_ID
}
};
ieis.Add(iei);
}
},"Tax");
}
This is the intermediate property:
//**********
class A
{
public B BasicInfo
{
get;
set;
}
class B
{
public X Tax
{
get;
set;
}
}
}
//***********
This is the class which sends through WS:
void WebServiceExecute(SomeType someParam)
{
//into ‚iai’ i store the data which comes from interface
var iai = base.Params.FetchOrDefault<A>( INFO, null);
var convertedObj = new IWEI();
//...
var lx = new List<X>();
//1st WAY: I tried to put all data from ‚Tax’into my local list ‚lx’
//lx.Add(iai.BasicInfo.Tax); - this way is not working
//2nd WAY: I tried to put data separately into ‚lx’
var iei = new X
{
service = new ServiceInfo
{
id = iai.BasicInfo.Tax.service.id
},
amount = iai.BasicInfo.Tax.amount,
currency = new CurrencyInfo
{
id = iai.BasicInfo.Tax.currency.id
}
};
lx.Add(iei);
// but also is not working
Can you help me please to suggest how to implement a way that will fine do the work (take data from ‚ieis’ and put her into ‚lx’).
Thank you so much
As noted in my comment, it looks like iai.BasicInfo.Tax is null, once you find out why that is null your original Add() (#1) will work.
I'm trying to create a collection of business objects from the following xml document using .net 4.0/c#
<WebServices ErrorFound="False" ServerDateTime="30/11/2010 14:58:58">
<Results>
<Users TotalResults="5">
<UserName UserID="2">John</UserName>
<UserName UserID="3">Dave</UserName>
<UserName UserID="4">Jim</UserName>
<UserName UserID="5">Bob</UserName>
</Users>
</Results>
</WebServices>
This is the class I need to create
public class User
{
public string Name { get; set; }
public int ID { get; set; }
}
Each of the Users child elements should be a new instance of the class.
So far I have this method which accepts an XmlDocument.
public static IEnumerable<User> GetUser(XmlDocument xmlDoc)
{
XmlReader reader = XmlReader.Create(new StringReader(xmlDoc.OuterXml));
XDocument doc = XDocument.Load(reader);
var user = from u in doc.Descendants("WebServices").DescendantsAndSelf("Users")
select new User()
{
Name = u.Element("UserName").Value,
ID = int.Parse(u.Element("UserName").Attribute("UserID").Value)
};
List<User> userInstance = user.ToList();
IEnumerable<User> users= from u in userInstance
select u;
return users;
}
This works fine as far as producing one instance of the object from the first child element is concerned but I am unsure as to how to create multiple instances from all the elements.
I need to be able to return a collection of the User objects eg Collection<User> users = new Collection<User>()
I could be barking up completely the wrong tree. Any help is much appreciated.
Using XPath you can write the code like this:
public class User
{
public string Name { get; set; }
public int ID { get; set; }
}
static void Main(string[] args)
{
string xml =
"<WebServices ErrorFound='False' ServerDateTime='30/11/2010 14:58:58'>" +
"<Results>" +
"<Users TotalResults='5'>" +
"<UserName UserID='2'>John</UserName>" +
"<UserName UserID='3'>Dave</UserName>" +
"<UserName UserID='4'>Jim</UserName>" +
"<UserName UserID='5'>Bob</UserName>" +
"</Users>" +
"</Results>" +
"</WebServices>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var users = from userNameElement in doc.SelectNodes("/WebServices/Results/Users/UserName").OfType<XmlElement>()
select new User
{
Name = userNameElement.InnerText,
ID = Int32.Parse(userNameElement.GetAttribute("UserID"))
};
foreach (var user in users)
{
Console.WriteLine(user.ID.ToString() + ": " + user.Name);
}
}
Ok, so I finally figured out what was wrong with my code.
Instead of
var user = from u in doc.Descendants("WebServices").DescendantsAndSelf("Users")
select new User()
{
Name = u.Element("UserName").Value,
ID = int.Parse(u.Element("UserName").Attribute("UserID").Value)
};
I now have
var user = (from u in doc.Descendants("UserName")
select new Provider()
{
Name = u.Value,
ID = int.Parse(u.Attribute("UserID").Value)
});
the statement: doc.Descendants("UserName") basically produces an array of the UserName elements which can be iterated through, I can then directly access the value of that element and set it to my class properties.
I have a simple xml doc I am reading, a sample is here:
<people>
<person>
<name>joe</name>
<age>21</age>
<contact>
<phone-nums>
<phone-num>
<number>123-4567</number>
<type>home</type>
</phone-num>
<phone-num>
<number>123-4567</number>
<type>office</type>
</phone-num>
</phone-nums>
</contact>
</person>
</people>
I read it in using HttpContent.ReadAsXElement() and then use Linq to create objects. My simple objects look something like this:
public class PeopleList : List<Person> { }
public class Person
{
public string name;
public int age;
public Contact contact;
}
public class Contact
{
public PhoneList phones;
}
public class PhoneList : List<Phone>{}
public class Phone
{
public string number;
public string type;
}
Ok, so now I have my class that reads it all in which is where I am getting hung up (it's an extension method in my code):
public PeopleList ReadAsPeopleList(this HttpContent content)
{
var people = content.ReadAsXElement();
var personQuery = from p in people.Elements("person")
select new Person()
{
name = p.Element("name").ValueOrDefault(),
age = p.Element("age").ValueOrDefault(),
contact = (from c in p.Elements("contact")
select new Contact()
{
//I don't know how to select a new list of phones into a contact here
}
};
PeopleList l = new PeopleList();
l.AddRange(personQuery);
return l;
}
I'm having trouble creating the contact type with the composite phone number list. Any help would be appreciated.
Note: I rewrote a simplified version of all of this here so
To get the collection of 'Phone' that needs to go in the contact, you could use this:
c.Elements("phone-num").Select(phone => new Phone()
{
number = phone.Element("number").Value,
type = phone.Element("type").Value
});
so you want
select new Contact()
{
PhoneList = c.Elements("phone-num").Select(phone => new Phone()
{
number = phone.Element("number").Value,
type = phone.Element("type").Value
})
}
This answer will be a bit skewed from your actual question, but may provide some direction to your eventual solution.
Consider using a List<T> for your collections rather than creating a BusinessObjectCollection : List<T>. Here's a good SO read that may be of interest: List or BusinessObjectCollection?
With that being said, this is a somewhat tweaked version of your classes; I've used properties instead of fields as well. And finally, since I've not worked with HTTPContext much, I thew together an example using a basic string. The method presented here should be easy enough to convert into an extension method for HTTPContext, though:
public static IEnumerable<Person> ReadAsPeopleList( string xml )
{
var doc = XDocument.Parse( xml );
var people = doc.Root.Elements( "person" )
.Select( x => new Person
{
Name = x.Element( "name" ).Value,
Age = int.Parse( x.Element( "age" ).Value ),
Contact = new Contact
{
Phones = x.Descendants( "phone-num" )
.Select( p => new Phone
{
Number = p.Element( "number" ).Value,
Type = p.Element( "type" ).Value
} )
}
}
);
return people;
}
private static string MyXml = #"
<people><person><name>joe</name><age>21</age><contact><phone-nums>
<phone-num><number>123-4567</number><type>home</type></phone-num>
<phone-num><number>123-4567</number><type>office</type></phone-num>
</phone-nums></contact></person><person><name>bill</name><age>30</age>
<contact><phone-nums><phone-num><number>123-4567</number><type>home</type>
</phone-num><phone-num><number>123-4567</number><type>office</type>
</phone-num></phone-nums></contact></person></people>";