我目前正在努力確定 json-string 反序列化器在 C# 中回傳的型別。我試圖創建一個基礎 TypeWHATEVER 類,其中 TypeX 和 TypeY 繼承自它們,但是每當我嘗試檢索具有該特定型別的實際物件時,它仍然不起作用,因為兩者都可以使用相同的建構式創建一個新實體。
假設我有 TypeX 和 TypeY。它們都有相似的建構式,例如:都有一個帶引數的建構式(字串 a,字串 b)。但是,TypeY 有一個帶引數的附加建構式,例如 (string a, string b, string c)。
現在,每當我在 TypeY 中使用額外的建構式,甚至只是使用類似的建構式時,它仍然不會產生我想要的結果(它仍然將它視為 TypeX 和 TypeY)......在其中一種方法中我不知道要回傳哪種型別,因為該物件是從 Json-String 反序列化的。還把 T 和 放在給物件支持的方法上,但它適用于兩個類,這不是我想要的......我什至在每個不同的底層 Type 類中都放了一個列舉,但自從型別也在基類中定義。
如何或什么是確定如何從有類似建構式的 json 字串中獲取實際物件型別的最佳方法,但它們仍然彼此不同......
請幫助我完成這個:(
下面你會找到我想要實作的示例代碼..
就像我之前說的,我有一個基類或介面沒關系,還有兩個子類
基類:例如 Parent.cs
public class Parent
{
public virtual ClassType Type { get; protected set; } = ClassType.Undefined;//this is an enum and used to differentiate between the different classes. However, this doesn't work, because of the parent type will always be Undefined whenever a child type is converted from json-string to explicit Parent type...
public string Id { get; set; }
public string Message { get; set; }
public Parent()
{
}
public Parent(string id, string message = "")
{
Id = id;
Message = message;
}
}
子類:例如 ChildA.cs
public class ChildA : Parent
{
public override ClassType Type => ClassType.Default;
public ChildA()
{
}
public ChildA(string id, string message = "") : base(id, message)
{
}
}
子類:例如 ChildB.cs
public class ChildB : Parent
{
private object testObjectA;
private object testObjectB;
private object testObjectC;
public override ClassType Type => ClassType.New;
public object TestObjectA
{
get { return testObjectA; }
set { testObjectA = value; }
}
public object TestObjectB
{
get { return testObjectB; }
set { testObjectB = value; }
}
public object TestObjectC
{
get { return testObjectC; }
set { testObjectC = value; }
}
public ChildB()
{
}
public ChildB(string id, string message) : base(id, message)
{
}
public ChildB(string id, IDictionary<string, object> collection, string message = "") : this(id, message) // should I use 'this' or 'base' here for id and message, because I already get the base class for the second constructor and it makes sense to me just to take this class since the other is already been using the base class?
{
testObjectA = collection[Constants.A];
testObjectB = collection[Constants.B];
testObjectC = collection[Constants.C];
}
}
Json 轉換器類:例如 JsonConverterClass.cs
public static T StringToObject<T>(string json)
=> JsonConvert.DeserializeObject<T>(json);//using Newtonsoft.Json;
現在我有一個想要轉換為 ChildA 或 ChildB 的 Json-String。Json-String 是這樣的:
{
"type": "New",//This is the ClassType for example
"id": "Some String...",
"message": "",
"collection": {
"objectA": "A",
"objectB": "B",
"objectC": "C",
}
}
讓我們嘗試轉換不起作用的 Json 字串并將該 Child 物件回傳到一個方法中,不幸的是這不起作用:
public Parent GetObjectExample(string json_String)
{
Parent parentClass = JsonConverterClass.StringToObject<Parent>(json_String);// I don't know how I maybe can use reflection here to accomplish, maybe this is an option too?
switch (parentClass.Type)
{
case ClassType.Default:
parentClass = parentClass as ChildA;
break;
case ClassType.New:
parentClass = parentClass as ChildB;
break;
}
return parentClass;
}
這里的問題是我希望 ChildB 會回饋。但是,由于兩個類具有相同的建構式。它不承認還給 ChildB。事實上,它只是回傳一個隨機類。 ChildA 或 ChilB,在大多數情況下,它只是回傳 ChildA 真正奇怪的東西。
希望我能盡可能清楚地告訴你發生了什么,我真的不知道為什么我的方法不起作用......
uj5u.com熱心網友回復:
好吧,我想有很多東西要評論。讓我們開始:
在具有 3 個引數的建構式中,使用this而不是base. 想象一下這種情況:
public ChildB(string id, string message)
: base(id, message)
{
this.FullName = $"{id} {message}";
}
public ChildB(string id, IDictionary<string, object> collection, string message = "")
: this(id, message)
{
}
呼叫this,您的 3 引數建構式運行設定FullName屬性的 2 引數建構式。如果你使用base,FullName將不會被初始化,你必須在你的 3 引數建構式中復制這一行。
C# 知道任何物件的型別。真的,你不需要你的ClassType財產。您可以執行以下操作:
if (myChildBInstance.GetType() == typeof(ChildB))
我建議您洗掉此屬性。
此外,該財產受到保護。您無法從序列化中更改它的值。序列化(默認情況下)適用于公共屬性。
我認為,您問題的關鍵在于建構式。序列化時,始終使用無引數建構式。在反序列化中,呼叫不帶引數的建構式,然后設定屬性。
您Type在 JSON 字串中的屬性永遠不會被使用。您無法設定該值,因為它是受保護的,并且您的實體是在您開始處理這些屬性之前創建的。
var json = @"{
'type': 'New',//This is the ClassType for example
'id': 'Some String...',
'message': '',
'collection': {
'objectA': 'A',
'objectB': 'B',
'objectC': 'C',
}
}";
var obj = StringToObject<ChildB>(json);
當您運行前面的代碼時,ChildB會創建一個物件(因為Ttype of StringToObject),然后設定所有 JSON 字串(公共)屬性。因此,您的 type 屬性不可能對選擇物件的型別有用。collection不是您的物件的屬性:這就是您的物件沒有獲得這些 A、B、C 值的原因。
使用此示例:
var childB = new ChildB
{
Id = "Id",
Message = "Msg",
TestObjectA = 1,
TestObjectB = 2,
TestObjectC = 3
};
var json = JsonConvert.SerializeObject(childB);
您的 JSON 必須是這樣的:
{
"TestObjectA":1,
"TestObjectB":2,
"TestObjectC":3,
"Id":"Id",
"Message":"Msg"
}
然后,您以這種方式獲得有效物件:
var obj = StringToObject<ChildB>(json);
如果您要使用不同的型別和繼承,那么您必須使用TypeNameHandling = TypeNameHandling.All我在鏈接https://stackoverflow.com/a/72270480/18452174之前評論過的內容。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/478587.html
