在 C# 中从 Json-String 检索特定类型的实际具体 Object 的最佳方法?
Best Way to Retrieve Actual Concrete Object Of a Certain Type From a Json-String in C#?
我目前正在努力确定 json-string 反序列化器在 C# 中返回哪些类型。我试图创建一个基础 TypeWHATEVER class ,其中 TypeX 和 TypeY 继承自它们,但每当我尝试检索具有该特定类型的实际 object 时,它都不起作用,因为两者都可以创建具有相同构造函数的新实例。
假设我有 TypeX 和 TypeY。它们都有相似的构造函数,例如:都有一个带有参数(字符串a,字符串b)的构造函数。但是TypeY多了一个带参数的构造函数,例如(string a, string b, string c).
现在每当我在 TypeY 中使用额外的构造函数或什至只是类似的构造函数时,它仍然不会产生我想要的结果(它仍然将它视为 TypeX 和 TypeY)...
在其中一种方法中,我不知道 return 是哪种类型,因为 object 是从 Json-String 反序列化的。同样将 T 和放在提供 object 支持的方法上,但它对两个 classes 都有效,这不是我想要的......我什至在每个不同的基础类型 classes,但这没有用,因为类型也在基础 class 中定义。
确定如何从 json 字符串中获取实际 object 类型的最佳方法或最佳方法是什么,其中有相似的构造函数,但它们仍然彼此不同...
请帮我解决这个问题:(
下面是我要实现的示例代码..
Like I said earlier I have a base class or interface doesn't matter and two child classes
基础Class:例如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;
}
}
Child Class:例如ChildA.cs
public class ChildA : Parent
{
public override ClassType Type => ClassType.Default;
public ChildA()
{
}
public ChildA(string id, string message = "") : base(id, message)
{
}
}
Child Class:例如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转换器Class:例如JsonConverterClass.cs
public static T StringToObject<T>(string json)
=> JsonConvert.DeserializeObject<T>(json);//using Newtonsoft.Json;
现在我有一个 Json-String,我想将其转换为 ChildA 或 ChildB。 Json-String 是这样的:
{
"type": "New",//This is the ClassType for example
"id": "Some String...",
"message": "",
"collection": {
"objectA": "A",
"objectB": "B",
"objectC": "C",
}
}
让我们尝试转换不起作用的 Json-string 并将 Child object 返回到方法中,不幸的是这不起作用:
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 回馈。但是,由于两个 classes 具有相同的构造函数。它无法识别返回 ChildB。事实上,它只是随机返回 class.. ChildA 或 ChilB,在大多数情况下它只是返回 ChildA 真的很奇怪。
希望我能尽可能清楚地告知您正在发生的事情,我真的不知道为什么我的方法不起作用...
好的,我觉得有很多东西要评论。让我们开始吧:
在具有 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 参数构造函数 运行 2 参数构造函数设置 FullName
属性。如果你使用 base
,FullName
将不会被初始化,你必须在你的 3 参数构造函数中复制这一行。
C# 知道任何对象的类型。真的,您不需要 ClassType
属性。您可以执行以下操作:
if (myChildBInstance.GetType() == typeof(ChildB))
我建议你删除这个 属性。
此外,属性 受到保护。您不能通过序列化更改它的值。序列化(默认情况下)适用于 public 属性。
我认为你的问题的关键在于构造函数。序列化时,始终使用无参数构造函数。在反序列化中,调用不带参数的构造函数,然后设置属性。
您在 JSON 字符串中的 Type
属性 永远不会被使用。您无法设置该值,因为它受到保护并且您的实例是在您开始处理这些属性之前创建的。
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
对象(因为 T
是 StringToObject
的类型)然后,所有 JSON设置字符串 (public) 属性。所以你的类型 属性 不可能对选择对象的类型有用。 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
我的 link .
我目前正在努力确定 json-string 反序列化器在 C# 中返回哪些类型。我试图创建一个基础 TypeWHATEVER class ,其中 TypeX 和 TypeY 继承自它们,但每当我尝试检索具有该特定类型的实际 object 时,它都不起作用,因为两者都可以创建具有相同构造函数的新实例。
假设我有 TypeX 和 TypeY。它们都有相似的构造函数,例如:都有一个带有参数(字符串a,字符串b)的构造函数。但是TypeY多了一个带参数的构造函数,例如(string a, string b, string c).
现在每当我在 TypeY 中使用额外的构造函数或什至只是类似的构造函数时,它仍然不会产生我想要的结果(它仍然将它视为 TypeX 和 TypeY)... 在其中一种方法中,我不知道 return 是哪种类型,因为 object 是从 Json-String 反序列化的。同样将 T 和放在提供 object 支持的方法上,但它对两个 classes 都有效,这不是我想要的......我什至在每个不同的基础类型 classes,但这没有用,因为类型也在基础 class 中定义。
确定如何从 json 字符串中获取实际 object 类型的最佳方法或最佳方法是什么,其中有相似的构造函数,但它们仍然彼此不同...
请帮我解决这个问题:(
下面是我要实现的示例代码..
Like I said earlier I have a base class or interface doesn't matter and two child classes
基础Class:例如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;
}
}
Child Class:例如ChildA.cs
public class ChildA : Parent
{
public override ClassType Type => ClassType.Default;
public ChildA()
{
}
public ChildA(string id, string message = "") : base(id, message)
{
}
}
Child Class:例如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转换器Class:例如JsonConverterClass.cs
public static T StringToObject<T>(string json)
=> JsonConvert.DeserializeObject<T>(json);//using Newtonsoft.Json;
现在我有一个 Json-String,我想将其转换为 ChildA 或 ChildB。 Json-String 是这样的:
{
"type": "New",//This is the ClassType for example
"id": "Some String...",
"message": "",
"collection": {
"objectA": "A",
"objectB": "B",
"objectC": "C",
}
}
让我们尝试转换不起作用的 Json-string 并将 Child object 返回到方法中,不幸的是这不起作用:
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 回馈。但是,由于两个 classes 具有相同的构造函数。它无法识别返回 ChildB。事实上,它只是随机返回 class.. ChildA 或 ChilB,在大多数情况下它只是返回 ChildA 真的很奇怪。
希望我能尽可能清楚地告知您正在发生的事情,我真的不知道为什么我的方法不起作用...
好的,我觉得有很多东西要评论。让我们开始吧:
在具有 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 参数构造函数 运行 2 参数构造函数设置 FullName
属性。如果你使用 base
,FullName
将不会被初始化,你必须在你的 3 参数构造函数中复制这一行。
C# 知道任何对象的类型。真的,您不需要 ClassType
属性。您可以执行以下操作:
if (myChildBInstance.GetType() == typeof(ChildB))
我建议你删除这个 属性。
此外,属性 受到保护。您不能通过序列化更改它的值。序列化(默认情况下)适用于 public 属性。
我认为你的问题的关键在于构造函数。序列化时,始终使用无参数构造函数。在反序列化中,调用不带参数的构造函数,然后设置属性。
您在 JSON 字符串中的 Type
属性 永远不会被使用。您无法设置该值,因为它受到保护并且您的实例是在您开始处理这些属性之前创建的。
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
对象(因为 T
是 StringToObject
的类型)然后,所有 JSON设置字符串 (public) 属性。所以你的类型 属性 不可能对选择对象的类型有用。 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
我的 link