你能在.NET中从JSON实例化一个对象实例吗
本文关键字:实例化 一个对象 实例 JSON 中从 NET | 更新日期: 2023-09-27 17:47:25
由于对象初始化器与JSON非常相似,现在.NET中有匿名类型。如果能够获取一个字符串(如JSON)并创建一个表示JSON字符串的匿名对象,那将是一件很酷的事情。
使用对象初始化程序创建匿名类型:
var person = new {
FirstName = "Chris",
LastName = "Johnson"
};
如果您可以传入Object Initializer代码的字符串表示(最好是类似JSON的代码),用该数据创建Anonymous Type的实例,那将是非常棒的。
我不知道这是否可能,因为C#不是动态的,编译器实际上将Object Initializer和Anonymous Type转换为可以运行的强类型代码。本文对此进行了解释。
也许采用JSON并用它创建键/值字典的功能最有效。
我知道你可以在.NET中将一个对象序列化/反序列化为JSON,但我想要的是一种创建本质上是松散类型的对象的方法,类似于JavaScript的工作方式。
有人知道在.NET中做这件事的最佳解决方案吗?
更新:太清楚了我为什么要问这个。。。我在思考C#如何在语言级别(可能)更好地支持JSON,出于概念上的原因,我试图思考今天可以做到这一点的方法。所以,我想我应该把它贴在这里开始讨论。
有些.NET语言有鸭子类型,但C#不可能使用Dot.Notation,因为C#要求在编译时解析所有成员引用。如果你想使用Dot.Notation,你仍然需要在某个地方定义一个具有所需属性的类,并使用任何你想从JSON数据实例化类的方法。预定义一个类确实有一些好处,比如强类型、IDE支持(包括intellisense),以及不用担心拼写错误。您仍然可以使用匿名类型:
T deserialize<T>(string jsonStr, T obj) { /* ... */}
var jsonString = "{FirstName='Chris', LastName='Johnson, Other='unused'}";
var person = deserialize(jsonString, new {FirstName="",LastName=""});
var x = person.FirstName; //strongly-typed
您应该查看JSON.net项目:
http://james.newtonking.com/pages/json-net.aspx
你基本上是在谈论从JSON中水合对象的能力,这将做到。它不会做匿名类型,但也许它会让你足够接近。
我写了一个相对较短的方法,它将解析JSON并返回一个名称/值字典,该字典可以像JavaScript中的实际对象一样访问。
以下是以下方法的示例用法:
var obj = ParseJsonToDictionary("{FirstName: '"Chris'", '"Address'":{Street:'"My Street'",Number:123}}");
// Access the Address.Number value
object streetNumber = ((Dictionary<string, object>)obj["Address"])["Number"];
下面是ParseJsonToDictionary方法的代码:
public static Dictionary<string, object> ParseJsonToDictionary(string json)
{
var d = new Dictionary<string, object>();
if (json.StartsWith("{"))
{
json = json.Remove(0, 1);
if (json.EndsWith("}"))
json = json.Substring(0, json.Length - 1);
}
json.Trim();
// Parse out Object Properties from JSON
while (json.Length > 0)
{
var beginProp = json.Substring(0, json.IndexOf(':'));
json = json.Substring(beginProp.Length);
var indexOfComma = json.IndexOf(',');
string endProp;
if (indexOfComma > -1)
{
endProp = json.Substring(0, indexOfComma);
json = json.Substring(endProp.Length);
}
else
{
endProp = json;
json = string.Empty;
}
var curlyIndex = endProp.IndexOf('{');
if (curlyIndex > -1)
{
var curlyCount = 1;
while (endProp.Substring(curlyIndex + 1).IndexOf("{") > -1)
{
curlyCount++;
curlyIndex = endProp.Substring(curlyIndex + 1).IndexOf("{");
}
while (curlyCount > 0)
{
endProp += json.Substring(0, json.IndexOf('}') + 1);
json = json.Remove(0, json.IndexOf('}') + 1);
curlyCount--;
}
}
json = json.Trim();
if (json.StartsWith(","))
json = json.Remove(0, 1);
json.Trim();
// Individual Property (Name/Value Pair) Is Isolated
var s = (beginProp + endProp).Trim();
// Now parse the name/value pair out and put into Dictionary
var name = s.Substring(0, s.IndexOf(":")).Trim();
var value = s.Substring(name.Length + 1).Trim();
if (name.StartsWith("'"") && name.EndsWith("'""))
{
name = name.Substring(1, name.Length - 2);
}
double valueNumberCheck;
if (value.StartsWith("'"") && value.StartsWith("'""))
{
// String Value
d.Add(name, value.Substring(1, value.Length - 2));
}
else if (value.StartsWith("{") && value.EndsWith("}"))
{
// JSON Value
d.Add(name, ParseJsonToDictionary(value));
}
else if (double.TryParse(value, out valueNumberCheck))
{
// Numeric Value
d.Add(name, valueNumberCheck);
}
else
d.Add(name, value);
}
return d;
}
我知道这个方法可能有点粗糙,可能会优化很多,但这是第一稿,它确实有效。
此外,在你抱怨它没有使用正则表达式之前,请记住,并不是每个人都真正理解正则表达式,如果需要的话,这样写会让其他人更难修复。此外,我目前还不太了解正则表达式,字符串解析更容易。
您不能从方法**返回匿名类型,因此"重新水合"的匿名类型的存在将仅限于重新水合的方法。有点毫无意义。
**你可以将它作为一个对象返回(这需要反射才能访问它的属性——yeech),也可以"以身作则",这也是毫无意义的,因为它需要额外的步骤,这意味着你已经知道对象的类型应该是什么样子,所以为什么不创建一个对象并首先填充它呢?
这方面的应用程序是什么?
出于几个原因,我不会走这条路。
-
第一;它可能需要大量使用反射之类的支持代码来创建您正在讨论的透明方法。
-
其次,正如您所说,C#是一种强类型语言,类似的东西被排除在语言规范之外是有原因的。
-
第三,这样做的开销是不值得的。记住,网页(尤其是AJAX查询)应该非常快,否则就达不到目的。如果你继续花费50%的时间在C#和Javascript之间序列化对象,那么你就有问题了。
我的解决方案是创建一个类,它只封装一个字典,并将JSON字符串作为ctor参数。然后,只需为要处理的每种类型的JSON查询扩展该类。这将是一个强类型、更快的解决方案,但仍然保持可扩展性和易用性。缺点是每种类型的JSON请求都要编写更多的代码。
:)