How to store multiple items in IDictionary? - c#

I have this IDictionary declaration: IDictionary<string, string> trace;
Inside of it I want save a list of element returned by a json deserialization, actually I do this like:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
trace["date"] = item.trace.details.date;
trace["type"] = item.trace.details.type;
foreach (var trace in item.trace.context.context)
{
trace["context"] = JsonConvert.SerializeObject(trace);
}
}
Now this code working good but save only the last item of the iteration, this 'cause when I iterate over the item the date, type etc... are replaced, but I want store the item not replace it in each new iteration.
How can do this with IDictionary?
Note that: trace.x is the name of the class that deserialize the json.
Further question: Maybe the use of IDictionary is not a good idea for achieve this?

Looks like you'd be better off using a dedicated class, something like this:
public class TraceInfo
{
public string Date { get; set; }
public string Type { get; set; }
public List<string> ContextItems { get; set; }
}
Then for every value in obj, create a TraceInfo object using new TraceInfo() and set its properties.
You can then store them in a List<TraceInfo> or in a Dictionary<string, TraceInfo>, the choice is yours.

Related

Apply Setter on XML Deserialize C# [duplicate]

I am trying to do a very simple bit of serialization with XmlSerializer:
public struct XmlPerson
{
[XmlAttribute] public string Id { get; set; }
[XmlAttribute] public string Name { get; set; }
}
public class GroupOfPeople
{
private Dictionary<string, string> _namesById = new Dictionary<string, string>();
//pseudo property for serialising dictionary to/from XML
public List<XmlPerson> _XmlPeople
{
get
{
var people = new List<XmlPerson>();
foreach (KeyValuePair<string, string> pair in _namesById )
people.Add(new XmlPerson() { Id = pair.Key, Name = pair.Value });
return people;
}
set
{
_namesById.Clear();
foreach (var person in value)
_namesById.Add(person.Id, person.Name);
}
}
}
Saving this class works fine, and I get:
<?xml version="1.0" encoding="utf-8"?>
<GroupOfPeople xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<_XmlPeople>
<XmlPerson Id="person1" Name="Fred" />
<XmlPerson Id="person2" Name="Bill" />
<XmlPerson Id="person3" Name="Andy" />
<XmlPerson Id="person4" Name="Nagesh" />
</_XmlPeople>
</GroupOfPeople>
However, when I read in the file again, my _XmlPeople property setter is never called, and thus the dictionary is empty. All other properties on this object get deserialized fine.
Am I missing something obvious? I have tried various collection types but none of them deserialize.
EDIT: Read code:
try
{
using (var stream = new StreamReader(itemPath))
{
var xml = new XmlSerializer(typeof(GroupOfPeople));
GroupOfPeople item = (GroupOfPeople)xml.Deserialize(stream);
}
}
//snip error stuff
Answer for clarity:
Have done some debugging and found that XmlSerializer does not call the setter for a collection.
Instead is calls the getter, and then adds items to the collection returned. Thus a solution such as Felipe's is necessary.
Have you tried using the XmlArray attribute?
With your example it would be something like this:
[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople
EDIT:
Here, try the following structure:
public struct XmlPerson
{
[XmlAttribute] public string Id { get; set; }
[XmlAttribute] public string Name { get; set; }
}
public class GroupOfPeople
{
[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople { get; set; }
}
I don't think it will be easy to add code to the Setter of the list, so what about getting that Dictionary when you actually need it?
Like this:
private Dictionary<string, string> _namesById;
public Dictionary<string, string> NamesById
{
set { _namesById = value; }
get
{
if (_namesById == null)
{
_namesById = new Dictionary<string, string>();
foreach (var person in XmlPeople)
{
_namesById.Add(person.Id, person.Name);
}
}
return _namesById;
}
}
This way you'll get the items from the XML and will also mantain that Dictionary of yours.
In this question, the _XmlPeople property serves as a "proxy" for the _namesById dictionary, which is where the collection elements are actually stored. Its getters and setters convert between different types of collections.
This does not work with deserialization, and the reason is pointed out in https://stackoverflow.com/a/10283576/2279059.
(Deserialization calls the getter, then adds elements to the "temporary" collection it returns, which is then discarded).
A generic solution is to implement the "proxy collection" as a separate class, then have a property which is a proxy collection:
(In the code below, the "actual collection" is _nameById, and MyItem is XmlPerson)
public class MyProxyCollection : IList<MyItem> {
MyProxyCollection(... /* reference to actual collection */ ...) {...}
// Implement IList here
}
public class MyModel {
MyProxyCollection _proxy;
public MyModel() {
_proxy = new MyProxyCollection (... /* reference to actual collection */ ...);
}
// Here we make sure the getter and setter always return a reference to the same
// collection object. This ensures that we add items to the correct collection on
// deserialization.
public MyProxyCollection Items {get; set;}
}
This ensures that getting/setting the collection object works as expected.

Deserialize JSON in c# when the return dataset in not known

I am working on census data and the url for my json is:
http://api.census.gov/data.json
From the above json i want to build the drop down of "title" where "c_dataset" have "acs5". Now the code in my MVC controller is as follows :
var yourObject = new JavaScriptSerializer().Deserialize<dynamic>(result.ToString());
foreach (KeyValuePair<string, object> currency in yourObject)
{
if (currency.Key == "dataset")
{
foreach (KeyValuePair<string, object> cur in currency.Value)
{
}
}
}
the inner most foreach gives me an error that "foreach statement can not operate on variable type 'object' because 'object' does not contain a public definition for 'GetEnumerator' !! i can not deserialize the object in certain class because this json is big. What could be the best way to do this ? Also, i was wondering if i can use the LINQ to query the deserialize object. Thanks in advance.
I think your best bet would be to build concrete type(s) that only have the properties you want, ignoring everything else. JSON deserializer will then ignore additional "noise" and only read the properties you specified.
// not tested
class CensusDataSet
{
[JsonProperty("c_dataset")]
public string[] CDataset { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
}
class CensusData
{
[JsonProperty("dataset")]
public CensusDataSet[] DataSets { get; set; }
}
...
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<CensusData>(content);
foreach (var dataSet in data.DataSets) ...
BTW, your title is misleading: what you are trying to do is called deserialize.

How to iterate over this particular type of Dictionary<int, Result>?

I have a bunch of results from the Database that I keep in a Dictionary<int, Result>().
The Result class I have is:
public int Id { get; set; }
public string something { get; set; }
public string somethingtwo { get; set; }
public string somethingthree { get; set; }
public DateTime Posted { get; set; }
public string Location { get; set; }
public bool somethingfour { get; set; }
So, the Dictionary<int, Result> has many Results inside and I'd like to iterate over them. How an I do this? I've tried a few ways, but even I knew they wouldn't work.
I would like to do something like this:
foreach(var result in resultDict)
{
mynewstring = result.Location;
mynewstringtwo = result.Posted;
// etc etc.
}
foreach(var kvp in resultsDict) {
//Do somethign with kvp
UseResult(kvp.Value); //kvp.Value is a Result object
UseKey(kvp.Key); //kvp.Key is the integer key you access it with
}
In the above code kvp is a KeyValuePair<int, Result>. You can access the Key and Value properties to get the integer key of the Dictionary and the Result value associated with that Key. I'll leave it as an excercise/guessing game for you to figure out which property is which! ;-)
As #Wiktor mentions, you can also access the dictionary's Values and Keys collections to do the same thing, but retrieve a sequence of int or Value properties instead.
Alternatives using the other collections:
foreach(var val in resultsDict.Values) {
// The key is not accessible immediately,
// you have to examine the value to figure out the key
UseResult(val); //val is a value.
}
foreach(var key in resultsDict.Keys) {
//The value isn't directly accessible, but you can look it up.
UseResult(resultsDict[key]);
UseKey(key);
}
Dcitionary has a ValueCollection called Values, so the code would be:
foreach (Result r in dict.Values)
{
mynewstring = result.Location;
mynewstringtwo = result.Posted;
}
var dictionary = ...;
foreach ( var result in dictionary.Values )
{
...
}
Is that what you need?
You can use the Values property to iterate over the values of a Dictionary (see also the MSDN page).
Code example:
// Your dictionary
var myResultDictionary = new Dictionary<int, Result>();
foreach (var item in myResultDictionary.Values)
{
// "item" holds a Result object
// Do something with item
}
You can also regularly loop over your Dictionary, however item will be a KeyValuePair (MSDN page) object. You can access the value with the Value property on the variable item.
Code example:
// Your dictionary
var myResultDictionary = new Dictionary<int, Result>();
foreach (var item in myResultDictionary)
{
// "item" holds a KeyValuePair<int, Result> object
// You can access the value (a Result object) by calling "item.Value"
// Do something with item
}
You can iterate over Dictionary.Values, which would be like any other IEnumerable<Result>
Or, you can iterate over Dictionary, which is an IEnumerable<KeyValuePair<int, Result>>
foreach (KeyValuePair<int,Result> item in dictionary)
{
//do stuff
}
foreach(KeyValuePair<int,result> keyValue in yourDictionary)
{
Debug.WriteLine(keyValue.Value);
//or
Debug.WriteLine(keyValue.Key);
}
or the same thing, but using var:
foreach(var keyValue in yourDictionary)
{
Debug.WriteLine(keyValue.Value);
//or
Debug.WriteLine(keyValue.Key);
}
^^ same thing, but var dynamically figures out its own type
or you can do this, if you just need the result:
foreach(var result in yourDictionary.Values)
{
Debug.WriteLine(result);
}
Use a foreach on the Dictionary:
foreach (var keyValue in dictionary)
{
//Use key value here
}

Setter not called when deserializing collection

I am trying to do a very simple bit of serialization with XmlSerializer:
public struct XmlPerson
{
[XmlAttribute] public string Id { get; set; }
[XmlAttribute] public string Name { get; set; }
}
public class GroupOfPeople
{
private Dictionary<string, string> _namesById = new Dictionary<string, string>();
//pseudo property for serialising dictionary to/from XML
public List<XmlPerson> _XmlPeople
{
get
{
var people = new List<XmlPerson>();
foreach (KeyValuePair<string, string> pair in _namesById )
people.Add(new XmlPerson() { Id = pair.Key, Name = pair.Value });
return people;
}
set
{
_namesById.Clear();
foreach (var person in value)
_namesById.Add(person.Id, person.Name);
}
}
}
Saving this class works fine, and I get:
<?xml version="1.0" encoding="utf-8"?>
<GroupOfPeople xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<_XmlPeople>
<XmlPerson Id="person1" Name="Fred" />
<XmlPerson Id="person2" Name="Bill" />
<XmlPerson Id="person3" Name="Andy" />
<XmlPerson Id="person4" Name="Nagesh" />
</_XmlPeople>
</GroupOfPeople>
However, when I read in the file again, my _XmlPeople property setter is never called, and thus the dictionary is empty. All other properties on this object get deserialized fine.
Am I missing something obvious? I have tried various collection types but none of them deserialize.
EDIT: Read code:
try
{
using (var stream = new StreamReader(itemPath))
{
var xml = new XmlSerializer(typeof(GroupOfPeople));
GroupOfPeople item = (GroupOfPeople)xml.Deserialize(stream);
}
}
//snip error stuff
Answer for clarity:
Have done some debugging and found that XmlSerializer does not call the setter for a collection.
Instead is calls the getter, and then adds items to the collection returned. Thus a solution such as Felipe's is necessary.
Have you tried using the XmlArray attribute?
With your example it would be something like this:
[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople
EDIT:
Here, try the following structure:
public struct XmlPerson
{
[XmlAttribute] public string Id { get; set; }
[XmlAttribute] public string Name { get; set; }
}
public class GroupOfPeople
{
[XmlArray]
[XmlArrayItem(ElementName="XmlPerson")]
public List<XmlPerson> XmlPeople { get; set; }
}
I don't think it will be easy to add code to the Setter of the list, so what about getting that Dictionary when you actually need it?
Like this:
private Dictionary<string, string> _namesById;
public Dictionary<string, string> NamesById
{
set { _namesById = value; }
get
{
if (_namesById == null)
{
_namesById = new Dictionary<string, string>();
foreach (var person in XmlPeople)
{
_namesById.Add(person.Id, person.Name);
}
}
return _namesById;
}
}
This way you'll get the items from the XML and will also mantain that Dictionary of yours.
In this question, the _XmlPeople property serves as a "proxy" for the _namesById dictionary, which is where the collection elements are actually stored. Its getters and setters convert between different types of collections.
This does not work with deserialization, and the reason is pointed out in https://stackoverflow.com/a/10283576/2279059.
(Deserialization calls the getter, then adds elements to the "temporary" collection it returns, which is then discarded).
A generic solution is to implement the "proxy collection" as a separate class, then have a property which is a proxy collection:
(In the code below, the "actual collection" is _nameById, and MyItem is XmlPerson)
public class MyProxyCollection : IList<MyItem> {
MyProxyCollection(... /* reference to actual collection */ ...) {...}
// Implement IList here
}
public class MyModel {
MyProxyCollection _proxy;
public MyModel() {
_proxy = new MyProxyCollection (... /* reference to actual collection */ ...);
}
// Here we make sure the getter and setter always return a reference to the same
// collection object. This ensures that we add items to the correct collection on
// deserialization.
public MyProxyCollection Items {get; set;}
}
This ensures that getting/setting the collection object works as expected.

Linq extracting objects

I have a JSON "multi-level" response that I need to deserialize and from the deserialized classes structure I need to extract all the objects of a certain class.
Below the code I'm using, at the end I find that my result is empty, not populated.
// given these two classes:
[DataContract]
public class ThingsList
{
[DataMember(Name = "status")]
public string Status { get; set; }
[DataMember(Name = "since")]
public double Since { get; set; }
[DataMember(Name = "list")]
public Dictionary<string, ThingsListItem> Items { get; set; }
public DateTime SinceDate { get { return UnixTime.ToDateTime(Since); } }
}
[DataContract]
public class ThingsListItem
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
}
// I can deserialize my json to this structure with:
ThingsList results = JsonConvert.DeserializeObject<ThingsList>(e.Result);
// now I need to "extract" only the ThingsListItem objects, and I'm trying this:
var theList = from item in results.Items.OfType<ThingsListItem>()
select new
{
Title = item.Title,
Url = item.Url
};
// but "theList" is not populated.
The points here are (I believe):
- I try to use results.Items.OfType() in order to extract only the ThingsListItem objects, that in the "upper" class are declared in the
public Dictionary Items { get; set; }
row.
Any idea? Tell if it's not clear...
Thanks
Andrea
EDIT: updated my response for clarity.
Since your Dictionary values are of type ThingsListItem you can access them directly by using the Dictionary's Values property. There is no need to use OfType to check their type and extract them. Simply use:
var items = results.Items.Values;
The Values property would return an ICollection<ThingsListItem>. You can then iterate over the results with a foreach. LINQ does not have to be used.
While the Values property described above should be sufficient, I will point out a few issues with your original LINQ query attempt.
1) The following query is probably what you were after. Again, the Dictionary's Values property is key (no pun intended) to accessing the items:
var theList = from item in results.Items.Values
select new
{
Title = item.Title,
Url = item.Url
};
2) Why are you using new? That will return an IEnumerable of anonymous types. You already have a defined class, so why project into a new anonymous type? You should retain the underlying ThingsListItem items by selecting the item directly to get an IEnumerable<ThingsListItem>:
var theList = from item in results.Items.Values
select item;
foreach (var item in theList)
{
Console.WriteLine("Title: {0}, Url: {1}", item.Title, item.Url);
}
You would usually project into a new anonymous type to define a type with data properties you are interested in. Generally you would use them immediately after the query, whereas a selection into an existing class could be used immediately or passed around to other methods that are expecting that type.
Hopefully this has cleared up some questions for you and you have a better idea of using LINQ and when to use the new keyword. To reiterate, for your purposes it seems the Values property should suffice. Using LINQ to select the item is redundant when there are other immediate means to do so.

Categories