tags:

views:

62

answers:

1

Hi all - 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

+2  A: 

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.

Ahmad Mageed
You can encapsulate the linq statement with .First() and it will return one ThingsListItem instead of a list of them.
Gage
Why the redundant LINQ query in the latter one? Just write `results.Items.Values` directly.
Timwi
@Timwi: I had just edited to mention that. Thanks for the feedback :)
Ahmad Mageed
The redundant LINQ query is still there.
Timwi
@Timwi: I clarified my response to emphasize the `Values` solution. However, I am keeping the LINQ queries to demonstrate the issues surrounding them and the `new` projection for the benefit of the OP.
Ahmad Mageed
thanks! - using simply "Values" it works.
ila