C
C#2mo ago
olayk

How to implement default indexing for my own JSONValue class

namespace JSONNS;

abstract class JSONValue;

class JSONNum(int val) : JSONValue {
public int Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}

class JSONString(string val) : JSONValue {
public string Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}

class JSONBool(bool val) : JSONValue {
public bool Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}

class JSONNull : JSONValue {
public static int? Val = null;
}

class JSONArray(List<JSONValue> val) : JSONValue {
public List<JSONValue> Val { get; set; } = val;
}

class JSONObject(Dictionary<string, JSONValue> val) : JSONValue {
public Dictionary<string, JSONValue> Val { get; set; } = val;
public JSONValue this[string s] { get => Val[s]; }
}
namespace JSONNS;

abstract class JSONValue;

class JSONNum(int val) : JSONValue {
public int Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}

class JSONString(string val) : JSONValue {
public string Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}

class JSONBool(bool val) : JSONValue {
public bool Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}

class JSONNull : JSONValue {
public static int? Val = null;
}

class JSONArray(List<JSONValue> val) : JSONValue {
public List<JSONValue> Val { get; set; } = val;
}

class JSONObject(Dictionary<string, JSONValue> val) : JSONValue {
public Dictionary<string, JSONValue> Val { get; set; } = val;
public JSONValue this[string s] { get => Val[s]; }
}
In another file I have a Parser class with Parser.parse() returning a JSONValue or throwing an error. Q1) If I have an abstract class as a return value / value does it enforces that it returns an instance of a child of this class? Q2) If I want to be able to index an unknown JSONValue (e.g. json['key1]['key2']) how should I do this? Would it work to have an abstract method for indexing, which returns an error on types such as JSONNumber? Q3) How could I enforce a Val in the JSONValue class? I would like to have a default ToString where I return the Val ToString which I would override on the JSONArray and JSONObject types, but I am not sure what type the Val could even be. Q4) Would it be a good idea to create my own error types for parsing, lexing and json indexing? Many thanks for any help! I'd appreciate any input on the code shown here also as I am new to C#. I'm not sure if this is the best way to create a type, so I'd appreciate any comments on a better way to implement this.
8 Replies
Pobiega
Pobiega2mo ago
C# has excellent JSON support already, but if you want to roll your own as a learning experience go ahead. That said, the usual approach to dealing with serialized content is to deserialize it to a normal C# class/record, not working with json primitives
olayk
olayk2mo ago
this is for learning, though i might look at the source for JSON in c# to see how it is done
Pobiega
Pobiega2mo ago
Q1 q2: yes Q3: object q4: yes, make your own exception base
olayk
olayk2mo ago
q3 im having problems with. i wrote something like public abstract object Val { get; set; } in JSONValue, but it then requires that the Val is of type object in each inherited class and I'm not sure how to get around that
Pobiega
Pobiega2mo ago
You will have to override it in the other classes
olayk
olayk2mo ago
class JSONNum(int val) : JSONValue {
public override object Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}
class JSONNum(int val) : JSONValue {
public override object Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
}
This works, but do i need to then store all of the string, bool, num, array and dict as just object?
Pobiega
Pobiega2mo ago
Ah, it only works for read-only properties, and only for covariant types
olayk
olayk2mo ago
is "Int" not narrower than object? i would have thought it was a type of object I have done this for the indexing part:
namespace JSONNS;

abstract class JSONValue {
public abstract JSONValue this[string s] { get; }
public abstract JSONValue this[int i] { get; }
}

class JSONNum(int val) : JSONValue {
public int Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONNum"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONNum"); }
}

class JSONString(string val) : JSONValue {
public string Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONString"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONString"); }
}

class JSONBool(bool val) : JSONValue {
public bool Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONBool"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONBool"); }
}

class JSONNull : JSONValue {
public static int? Val = null;
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONNull"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONNull"); }
}

class JSONArray(List<JSONValue> val) : JSONValue {
public List<JSONValue> Val { get; set; } = val;
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Type JSONArray cannot be indexed via string"); }
public override JSONValue this[int i] { get => Val[i]; }

}
namespace JSONNS;

abstract class JSONValue {
public abstract JSONValue this[string s] { get; }
public abstract JSONValue this[int i] { get; }
}

class JSONNum(int val) : JSONValue {
public int Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONNum"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONNum"); }
}

class JSONString(string val) : JSONValue {
public string Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONString"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONString"); }
}

class JSONBool(bool val) : JSONValue {
public bool Val { get; set; } = val;
public override string ToString() { return $"{Val}"; }
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONBool"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONBool"); }
}

class JSONNull : JSONValue {
public static int? Val = null;
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Cannot index type JSONNull"); }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Cannot index type JSONNull"); }
}

class JSONArray(List<JSONValue> val) : JSONValue {
public List<JSONValue> Val { get; set; } = val;
public override JSONValue this[string s] { get => throw new IndexOutOfRangeException("Type JSONArray cannot be indexed via string"); }
public override JSONValue this[int i] { get => Val[i]; }

}
class JSONObject(Dictionary<string, JSONValue> val) : JSONValue {
public Dictionary<string, JSONValue> Val { get; set; } = val;
public override JSONValue this[string s] { get => Val[s]; }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Type JSONArray cannot be indexed via int"); }
}
class JSONObject(Dictionary<string, JSONValue> val) : JSONValue {
public Dictionary<string, JSONValue> Val { get; set; } = val;
public override JSONValue this[string s] { get => Val[s]; }
public override JSONValue this[int i] { get => throw new IndexOutOfRangeException("Type JSONArray cannot be indexed via int"); }
}
is this a good implementation or is it better to have something like a JSONNotIndexable class which Num, String, Bool and Null inherit from?