代码之家  ›  专栏  ›  技术社区  ›  Chris Pietschmann

你能在.NET中通过JSON实例化一个对象实例吗?

  •  8
  • Chris Pietschmann  · 技术社区  · 16 年前

    因为对象初始值设定项与JSON非常相似,现在.NET中有匿名类型。能够获取一个字符串(如JSON)并创建一个表示JSON字符串的匿名对象是很酷的。

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

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

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

    我不知道是否可能,因为C不是动态的,编译器实际上将对象初始值设定项转换为 d Anonymous Type into strongly typed code that can run. This is explained in 这篇文章。

    也许使用JSON并用它创建一个键/值字典的功能是最好的。

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

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

    更新:也要澄清我为什么要问这个…我在想C如何在语言级别(可能)更好地支持JSON,并且出于概念上的原因,我试图思考今天可以实现JSON的方法。所以,我想我应该把它贴在这里开始讨论。

    5 回复  |  直到 16 年前
        1
  •  6
  •   Mark Cidade    16 年前

    有一些.NET语言有duck类型,但是使用点标记的C是不可能的,因为C要求在编译时解析所有成员引用。如果您想要使用dot.notation,您仍然需要在某个地方定义一个具有所需属性的类,并使用您想要从JSON数据实例化该类的任何方法。预先定义类 具有强大的打字功能、包括IntelliSense在内的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
    
        2
  •  5
  •   Jason Jackson    16 年前

    你应该去看看 JSON.NET 项目:

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

    您基本上是在讨论从JSON中为对象添加水合物的能力,这是可以做到的。它不会做匿名类型,但可能会让你足够接近。

        3
  •  4
  •   Chris Pietschmann    16 年前

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

    下面是parsejsontDictionary方法的代码:

    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;
    }
    

    我知道这个方法可能有点粗糙,它可能会被优化很多,但它是第一个草稿,而且它只是工作。

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

        4
  •  1
  •   Will    16 年前

    您不能从方法**返回匿名类型,因此,“再水化”匿名类型的存在将仅限于其被再水化的方法。有点毫无意义。

    **您可以将它作为一个对象返回(需要反射才能访问它的属性——Yeech),或者您可以“通过示例强制转换”,这也是毫无意义的,因为它需要额外的步骤,这意味着您已经知道对象的类型应该是什么样的,那么为什么不先创建一个对象并填充它呢?

        5
  •  0
  •   nlaq    16 年前

    这个应用程序是什么?

    我不会沿着这条路走,有几个原因。

    • 首先,可能需要使用反射等大量支持代码来创建您正在讨论的透明方法。

    • 第二,如您所说,C是一种强类型语言,因为某种原因,这种语言被排除在语言规范之外。

    • 第三,这样做的开销不值得。记住,网页(尤其是Ajax查询)应该非常快,否则会破坏目标。如果你继续在C和JavaScript之间花费50%的串行化你的对象,那么你会遇到一个问题。

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

    :)