您可以在 .NET 中从 JSON 实例化对象实例吗?

Can you Instantiate an Object Instance from JSON in .NET?

提问人:Chris Pietschmann 提问时间:10/14/2008 最后编辑:Chris Pietschmann 更新时间:11/19/2008 访问量:18135

问:

由于对象初始值设定项与 JSON 非常相似,因此现在 .NET 中有匿名类型。如果能够获取字符串(例如 JSON)并创建一个表示 JSON 字符串的匿名对象,那就太酷了。

使用对象初始值设定项创建匿名类型:

var person = new {
    FirstName = "Chris",
    LastName = "Johnson"
};

如果您可以传入对象初始值设定项代码的字符串表示形式(最好是类似 JSON)以使用该数据创建匿名类型的实例,那就太棒了。

我不知道这是否可能,因为 C# 不是动态的,编译器实际上将对象初始值设定项和匿名类型转换为可以运行的强类型代码。本文对此进行了解释

也许采用JSON并用它创建键/值字典的功能效果最好。

我知道您可以在 .NET 中将对象序列化/反序列化为 JSON,但我正在寻找一种创建本质上是松散类型的对象的方法,类似于 JavaScript 的工作方式。

有谁知道在.NET中执行此操作的最佳解决方案?

更新:也澄清一下我为什么问这个的背景......我当时在思考 C# 如何在语言级别(可能)更好地支持 JSON,并且出于概念原因,我试图想出今天可以做到的方法。所以,我想我会把它贴在这里开始讨论。

C# JavaScript JSON 匿名类型 对象初始值设定项

评论


答:

0赞 user19302 10/14/2008 #1

这有什么应用?

出于几个原因,我不会走这条路。

  • 第一;它可能需要大量使用反射等的支持代码来创建您正在谈论的透明方法。

  • 其次,就像你说的,C#是一种强类型语言,像这样的东西被排除在语言规范之外是有原因的。

  • 第三,这样做的开销是不值得的。请记住,网页(尤其是 AJAX 查询)应该非常快,否则就违背了目的。如果您继续花费 50% 的时间在 C# 和 Javascript 之间序列化您的对象,那么您就有问题了。

我的解决方案是创建一个只封装字典并将 JSON 字符串作为 ctor 参数的类。然后,只需为要处理的每种类型的 JSON 查询扩展该类即可。这将是一个强类型且速度更快的解决方案,但仍保持可扩展性和易用性。缺点是每种类型的 JSON 请求需要编写更多代码。

:)

8赞 Mark Cidade 10/14/2008 #2

有些 .NET 语言具有鸭子类型,但使用 Dot.Notation 的 C# 是不可能的,因为 C# 要求在编译时解析所有成员引用。如果要使用 Dot.Notation,仍必须在具有所需属性的某处定义一个类,并使用要从 JSON 数据实例化该类的任何方法。预定义类确实有好处,例如强类型化、IDE 支持(包括智能感知)以及不必担心拼写错误。您仍然可以使用匿名类型:

 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

评论

0赞 user7116 10/14/2008
+1,肮脏,但目前是做 OP 想要的唯一方法。
0赞 Chris Pietschmann 10/14/2008
非常好,这是我没有想到的一种方式。
0赞 Shekhar_Pro 5/6/2011
你认为答案是什么,因为现在 C# 支持动态类型
6赞 Jason Jackson 10/14/2008 #3

您应该查看 JSON.net 项目:

http://james.newtonking.com/pages/json-net.aspx

你基本上是在谈论从 JSON 中冻结对象的能力,这将做到这一点。它不会做匿名类型,但也许它会让你足够接近。

1赞 user1228 10/14/2008 #4

不能从方法**返回匿名类型,因此“解除冻结”匿名类型的存在将仅限于对其进行冻结的方法。有点毫无意义。

** 你可以把它作为一个对象返回(这需要反射来访问它的属性--是的),或者你可以“通过示例来投射它”,这也是没有意义的,因为它需要额外的步骤,这意味着你已经知道对象的类型应该是什么样子,那么为什么不首先创建一个对象并填充它呢?

4赞 Chris Pietschmann 10/14/2008 #5

我编写了一个相对较短的方法,它将解析 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;
}

我知道这种方法可能有点粗糙,它可能会优化很多,但它是初稿,它只是有效。

此外,在你抱怨它不使用正则表达式之前,请记住,并不是每个人都真正理解正则表达式,如果需要,这样写会让其他人更难修复。另外,我目前不太了解正则表达式,字符串解析更容易。