this is a kind of data i have to de-serialize
{
"id": "M:11427",
"title": "DAX30",
"nextStartId": "S:727831",
"sections": [
{
"type": "HIGHLIGHTS",
"baseResults": [ values of type highlights ],
"hasMore": true
},
{
"type": "CHART",
"hasMore": false,
"chartTypes": [ string values ]
},
{
"type": "TWEETS",
"baseResults": [ values of type tweets ],
"hasMore": true
}]
}
I have to serialize & deserialize them all. I want to create something that can hold the values corresponding to baseResults.
there is a main class that represent the whole json
class Data
{
...
ObservableCollection<Section> sections{get;set;}
...
}
then there is a class that represents the data in sections array of main json
class Section
{
string type{get;set;}// thi elements decides what kind of data would be in baseResults
dynamic baseResults{get;set;} //it should hold ObservableCollection of either Highlights or Tweets etc.
}
base class for type of data coming in baseResults array is an abstract class class CategoryData
and its children are class Highlights
& class Tweets
I am using dynamic
since I can not assign an ObservableCollection<CategoryData>
with ObservableCollection<Highlights>
. But I don't want to use this dynamic or object type instead I want something relevant. please suggest me what could be a better approach for this problem.
-
Do you do the serialization&deserialization manually, or do you use some library?Euphoric– Euphoric2014年03月21日 14:16:57 +00:00Commented Mar 21, 2014 at 14:16
-
@Euphoric basically I am using newtonsoft-json library. but for this particular json, i had to do manual de/serialization.Ankit– Ankit2014年03月21日 14:34:47 +00:00Commented Mar 21, 2014 at 14:34
3 Answers 3
If I'm understanding you correctly, you're trying to find a statically-typed way to say "a value of type Section
can be either a value of type Highlights
, Chart
, or Tweets
". There are many terms for this, including tagged union, discriminated union, variant, or sum type but they all refer to the same concept. Sum types are a standard feature in statically-typed functional programming languages, but with a bit of ingenuity you can roll your own in C#. Using that answer as a template, and adding sealed
to make sure no one adds any extra subclasses, your Section
type would look something like this:
public abstract class Section
{
// Prevent subclassing outside of this scope
private Section() {}
// Subclass implementation calls the appropriate function.
public abstract R Match<R>(Func<H, R> IfHighlight, Func<C, R> IfChart, Func<T, R> IfTweet);
// Convenience wrapper for when the caller doesn't want to return a value
// from the match expression.
public sealed void Match(Action<H> IfHighlight, Action<C> IfChart, Action<T> IfTweet)
{
this.Match<int>(
IfHighlight: Section => { IfHighlight(Section); return 0; },
IfChart: Section => { IfChart(Section); return 0; },
IfTweet: Section => { IfTweet(Section); return 0; }
);
}
// From here on down, you define your specific types as usual, and override Match to call
// the correct function
public sealed class Highlight : Section
{
// Implementation goes here
public override R Match<R>(Func<H, R> IfHighlight, Func<C, R> IfChart, Func<T, R> IfTweet)
{
return IfHighlight(this);
}
}
public class Chart : Section
{
// Implementation goes here
public override R Match<R>(Func<H, R> IfHighlight, Func<C, R> IfChart, Func<T, R> IfTweet)
{
return IfChart(this);
}
}
public class Tweet : Section
{
// Implementation goes here
public override R Match<R>(Func<H, R> IfHighlight, Func<C, R> IfChart, Func<T, R> IfTweet)
{
return IfTweet(this);
}
}
}
With that in place, you can declare variables of type Section
, and act on them by passing 3 functions to the Match
methods:
Section section = deserializeJson()
section.Match(
IfHighlight: highlight => /* code to use if you get a Highlight */
IfChart: chart => /* ... */
IfTweet: tweet => /* ... */
);
You could just as easily have a collection of Section
s and operate on them that way when you iterate over it.
How about using generics:
class Section<TCategoryData> where TCategoryData : CategoryData
{
string type{get;set;}
ObservableCollection<TCategoryData> baseResults{get;set;}
}
class HighlightSection : Section<Highlights> {}
class TweetSection : Section<Tweets> {}
-
this would not work, as I have to decide which class to instantiate based on type which is a member of Section itself.Ankit– Ankit2014年03月21日 12:50:40 +00:00Commented Mar 21, 2014 at 12:50
-
So how do you expect it to be statically typed?Uri Agassi– Uri Agassi2014年03月21日 12:58:09 +00:00Commented Mar 21, 2014 at 12:58
-
I was looking for something equivalent of wildcard of java however I don't think its possible, but is there no better way to handle it or would u suggest having ObservableCollection<object> is the only better possible way?Ankit– Ankit2014年03月21日 13:02:38 +00:00Commented Mar 21, 2014 at 13:02
-
You mean
ObservableObject<CategoryData>
? Yes, and I believe it will be as good as wildcards is this (read only) use caseUri Agassi– Uri Agassi2014年03月21日 14:00:22 +00:00Commented Mar 21, 2014 at 14:00
You are supposed to choose concrete subtype of Section
BEFORE you create the instance. The type
property should not even be in a Section
and should be tied to what subclass the instance is.
But how to do this depends on how you are doing the serialization and deserialization.