【问题标题】:Templated serialization of C# objects to JSON将 C# 对象模板化序列化为 JSON
【发布时间】:2012-02-07 10:25:13
【问题描述】:

我需要将对象序列化为 JSON。我想使用 template 而不是使用数据注释(就像大多数框架一样)。有人知道这样做的好方法吗?

一张图片可以说超过 1000 个单词。我正在寻找看起来像这样的东西:

例如,如果我有这样的课程:

public class Test  
{ 
    public string Key { get; set; } 
    public string Name { get; set; } 
    public string Code { get; set; } 
    public Test Related { get; set; } 
} 

还有一个模板字符串,可能看起来像这样:

{ 
    id: "$Key",
    name: "$Name",
    related: "$Related.Name"
}

我要获取一个JSON对象,根据对象的KeyNameRelated.Name填写属性。

基本上,我正在寻找 JSON 序列化 方法,该方法支持模板化

【问题讨论】:

  • 不清楚你到底想要什么。您是否要创建一个方法,该方法对该模板进行硬编码并适用于具有KeyNameRelated.Name 的任何类型?还是您想要一个完整的系统,可以理解您指定格式的模板并使用它们进行序列化?
  • @KeesC.Bakker 不需要任何人来解释反对票,因为反对票是匿名的。此外,这个问题没有显示任何研究工作,而且非常模糊(并且可以说它也没有建设性,因为您基本上是在询问产品/项目列表)。
  • @casperOne,我不同意这个问题没有建设性。它询问如何做一件特定的事情。我认为可以以适合 SO 的方式合理地回答它,至少以目前的形式。 (我重新编辑了模板示例并试图对其进行更多解释。)
  • @casperOne 请多解释一下?我该如何改进这个问题?
  • @KeesC.Bakker 您必须意识到您仍然在问一个非常广泛的问题(请参阅先前的评论),这就是问题的根源。同样,如果人们觉得这值得打开,那么他们会投票打开它。主持人关闭是可逆的。

标签: c# .net json


【解决方案1】:

我不知道有什么库可以为你做这件事,但你自己构建它并不难。

如果您有模板,则需要将其解析为 JSON,然后将所有占位符替换为实际值。为此,您可以使用访问者模式。

由于 JSON.NET(我正在使用的 JSON 库)似乎没有访问者,您可以自己创建一个:

abstract class JsonVisitor
{
    public virtual JToken Visit(JToken token)
    {
        var clone = token.DeepClone();
        return VisitInternal(clone);
    }

    protected virtual JToken VisitInternal(JToken token)
    {
        switch (token.Type)
        {
        case JTokenType.Object:
            return VisitObject((JObject)token);
        case JTokenType.Property:
            return VisitProperty((JProperty)token);
        case JTokenType.Array:
            return VisitArray((JArray)token);
        case JTokenType.String:
        case JTokenType.Integer:
        case JTokenType.Float:
        case JTokenType.Date:
        case JTokenType.Boolean:
        case JTokenType.Null:
            return VisitValue((JValue)token);
        default:
            throw new InvalidOperationException();
        }
    }

    protected virtual JToken VisitObject(JObject obj)
    {
        foreach (var property in obj.Properties())
            VisitInternal(property);

        return obj;
    }

    protected virtual JToken VisitProperty(JProperty property)
    {
        VisitInternal(property.Value);

        return property;
    }

    protected virtual JToken VisitArray(JArray array)
    {
        foreach (var item in array)
            VisitInternal(item);

        return array;
    }

    protected virtual JToken VisitValue(JValue value)
    {
        return value;
    }
}

然后创建一个专门的访问者,用实际值替换占位符:

class JsonTemplateVisitor : JsonVisitor
{
    private readonly object m_data;

    private JsonTemplateVisitor(object data)
    {
        m_data = data;
    }

    public static JToken Serialize(object data, string templateString)
    {
        return Serialize(
            data, (JToken)JsonConvert.DeserializeObject(templateString));
    }

    public static JToken Serialize(object data, JToken template)
    {
        var visitor = new JsonTemplateVisitor(data);

        return visitor.Visit(template);
    }

    protected override JToken VisitValue(JValue value)
    {
        if (value.Type == JTokenType.String)
        {
            var s = (string)value.Value;

            if (s.StartsWith("$"))
            {
                string path = s.Substring(1);

                var newValue = GetValue(m_data, path);

                var newValueToken = new JValue(newValue);

                value.Replace(newValueToken);

                return newValueToken;
            }
        }

        return value;
    }

    private static object GetValue(object data, string path)
    {
        var parts = path.Split('.');

        foreach (var part in parts)
        {
            if (data == null)
                break;

            data = data.GetType()
                .GetProperty(part)
                .GetValue(data, null);
        }

        return data;
    }
}

那么用法就很简单了。例如,使用以下模板:

{ 
    id : "$Key",
    name: "$Name",
    additionalInfo:
    {
        related: [ "$Related.Name" ]
    }
}

你可以使用这样的代码:

JsonTemplateVisitor.Serialize(data, templateString)

然后结果如下所示:

{
  "id": "someKey",
  "name": "Isaac",
  "additionalInfo": {
    "related": [
      "Arthur"
    ]
  }
}

您可能想要添加一些错误检查,但除此之外,代码应该可以工作。此外,它使用反射,因此如果性能很重要,它可能不适合。

【讨论】:

  • 我明天试试。看起来很有希望!感谢您的努力。
【解决方案2】:

如果您正在寻找通用的 json 序列化程序,不太清楚您所说的模板是什么意思。您可以在http://servicestack.net/ 下找到适用于 .NET 的最快 Json 序列化程序之一。

要从包管理器控制台安装此包,您可以执行以下命令。

      PM> Install-Package ServiceStack.Text

【讨论】:

  • 这似乎没有回答这个问题。这不仅仅是关于 JSON 序列化程序。
  • Svick 是对的,我正在寻找序列化程序和模板化我想要序列化的属性的方法。
  • @KeesC.Bakker 我不明白为什么我被否决了?我想我在回答中明确表示,我不明白你所说的模板是什么意思,我的回答只是针对 json 序列化。现在有了这张图片,我确切地知道你想要实现什么。
【解决方案3】:

ServiceStack 似乎是一个不错的选择。

http://www.servicestack.net/benchmarks/

【讨论】:

  • 这似乎没有回答这个问题。这不仅仅是关于 JSON 序列化程序。
  • Svick 是对的,我正在寻找序列化程序和模板化我想要序列化的属性的方法。
  • @svick,投反对票是为了什么?当我添加我的答案时,@Kees C. Bakker 还没有上传他的 1000 字值得图片。
  • 但我想已经很清楚这不是他想要的。
【解决方案4】:

您还可以为您的 json 模板使用文本模板文件。模板引擎将填写空白并返回结果。 如果您使用的是 Visual Studio,

  1. 创建一个.tt文件,
  2. 在文件的自定义工具属性中用 TextTemplatingFilePreprocessor 标记它。这将为您创建一个负责处理模板的新类。
  3. 要将您的数据集成到结果字符串中,请将新生成的类扩展为一个单独的文件,您可以在其中传递数据(图像中的任意类)。
  4. 用这个来获取json格式的代码;

    我的数据数据 = ...; MyTemplatePage page = new MyTemplatePage(data); String pageContent = page.TransformText();

现在 pageContent 有了 json 格式的字符串;有关如何处理 .tt 文件的更多详细信息,请查看此处:Text Template Control Blocks

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多