JsonObjectAttribute在运行时强制对象序列化

时间:2016-04-11 20:51:38

标签: c# json.net

JsonObjectAttribute可用于序列化实现IEnumerable<的类。 T>作为JSON对象而不是JSON数组

可以找到一个完美的例子here

由于我拥有控件,因此我可以使用自己定义的类。 但是当我尝试编写一个程序来处理第三方库时,我无法在这些类上添加JsonObjectAttribute。

是否有另一种方法可以告诉JsonConvert.SerializeObject执行类似JsonObjectAttribute的操作?

更新:

以下是我从Json.net文档中复制和粘贴的示例。

 [JsonObject]
 public class Directory : IEnumerable<string>
 {
     public string Name { get; set; }
     public IList<string> Files { get; set; }

     public Directory()
     {
         Files = new List<string>();
    }

    public IEnumerator<string> GetEnumerator()
    {
        return Files.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

 Directory directory = new Directory
 {
     Name = "My Documents",
     Files =
     {
         "ImportantLegalDocuments.docx",
         "WiseFinancalAdvice.xlsx"
     }
 };

string json = JsonConvert.SerializeObject(directory, Formatting.Indented);

Console.WriteLine(json);
// {
//   "Name": "My Documents",
//   "Files": [
//     "ImportantLegalDocuments.docx",
//     "WiseFinancalAdvice.xlsx"
//   ]
// }

现在,只要想到[JsonObject]不在该类定义上,那么如何才能获得相同的结果呢?

1 个答案:

答案 0 :(得分:1)

您可以创建一个custom contract resolver来维护应该序列化为对象的类型列表:

public class ObjectOverrideContractResolver : DefaultContractResolver
{
    readonly HashSet<Type> overrideObjectTypes;

    public ObjectOverrideContractResolver(IEnumerable<Type> overrideObjectTypes)
    {
        if (overrideObjectTypes == null)
            throw new ArgumentNullException();
        this.overrideObjectTypes = new HashSet<Type>(overrideObjectTypes);
    }

    protected override JsonContract CreateContract(Type objectType)
    {
        if (overrideObjectTypes.Contains(objectType))
        {
            var contract = CreateObjectContract(objectType);
            // Mark get-only properties like Count as ignored 
            foreach (var property in contract.Properties)
            {
                if (!property.Writable)
                    property.Ignored = true;
            }
            return contract;
        }
        else
        {
            var contract = base.CreateContract(objectType);
            return contract;
        }
    }
}

然后在JsonSerializerSettings.ContractResolver中设置:

var resolver = new ObjectOverrideContractResolver(new[] { typeof(Directory) });
var settings = new JsonSerializerSettings { ContractResolver = resolver };

var json = JsonConvert.SerializeObject(directory, Formatting.Indented, settings);

这会产生您需要的输出。如果需要,可以增强它以检查类型或其任何基类型是否在哈希表中(如果需要)。

请注意,为了获得最佳效果,您应该cache and reuse contract resolvers