Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Json.NET序列化期间向所有类添加自定义类型名_C#_.net_Serialization_Json.net - Fatal编程技术网

C# 在Json.NET序列化期间向所有类添加自定义类型名

C# 在Json.NET序列化期间向所有类添加自定义类型名,c#,.net,serialization,json.net,C#,.net,Serialization,Json.net,我需要向使用Json.Net序列化的每个对象添加一个“type”属性。我知道Json.Net已经支持这种开箱即用的方式,但是在我的例子中,类型名需要排除程序集,并且属性名必须是可配置的(两者都不支持) 我目前有: public class TypeConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serialiser)

我需要向使用Json.Net序列化的每个对象添加一个“type”属性。我知道Json.Net已经支持这种开箱即用的方式,但是在我的例子中,类型名需要排除程序集,并且属性名必须是可配置的(两者都不支持)

我目前有:

public class TypeConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serialiser)
    {
        JObject jObject = JObject.FromObject(value, serializer);
        jObject.AddFirst(new JProperty("myCustomTypePropertyName"), value.GetType().Name);
        jObject.WriteTo(writer);
    }

    public override void ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serialiser)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsClass;
    }
}
这适用于正在序列化的外部类型,但不幸的是,没有为嵌套对象调用转换器。如果我将serialiser添加到JObject.FromObject调用中,那么当它尝试为外部类型重新输入转换器时,会出现一个自引用循环异常

我可以绕过这个问题的唯一方法是在每个级别手动反射和迭代属性,并使用serializer参数对它们进行序列化,但这非常难看,甚至在考虑性能之前

我希望在这方面能得到一些帮助;我希望我错过了一些明显的东西


(注意:我正在运行.NET3.5,所以序列化绑定是不可能的。)

不,您没有遗漏任何明显的内容。尝试使用处理各种类型的类的
JsonConverter
来实现这一点是有问题的,原因您已经看到了。JSONConverter最适合处理特定类型;他们不太擅长概括。 幸运的是,有一种方法可以使用自定义的
IContractResolver
实现您想要的功能

契约解析器允许我们在广泛的类的属性级别应用某些序列化行为。其思想是让解析器在每个类上伪造一个额外的“type name”属性(或您希望调用的任何属性),并安装相应的
IValueProvider
,以便在序列化每个对象时为该属性提供值。(这样,序列化程序永远不会知道该属性实际上不存在。)

创建解析器的最简单方法是从Json.Net附带的
DefaultContractResolver
派生它。从那里,我们只需要重写
CreateProperties()
方法,并将伪属性注入从基类返回的列表中

以下是解析程序和值提供程序的代码:

class CustomResolver : DefaultContractResolver
{
    private string customTypePropertyName;
    private IValueProvider valueProvider = new SimpleTypeNameProvider();

    public CustomResolver(string customTypePropertyName)
    {
        this.customTypePropertyName = customTypePropertyName;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);

        if (type.IsClass && type != typeof(string))
        {
            // Add a phantom string property to every class which will resolve 
            // to the simple type name of the class (via the value provider)
            // during serialization.
            props.Insert(0, new JsonProperty
            {
                DeclaringType = type,
                PropertyType = typeof(string),
                PropertyName = customTypePropertyName,
                ValueProvider = valueProvider,
                Readable = true,
                Writable = false
            });
        }

        return props;
    }

    class SimpleTypeNameProvider : IValueProvider
    {
        public object GetValue(object target)
        {
            return target.GetType().Name;
        }

        public void SetValue(object target, object value)
        {
            return;
        }
    }
}
输出:

{
  "MyTypeName": "Person",
  "Id": 2,
  "Name": "Peter",
  "Employer": {
    "MyTypeName": "Company",
    "Id": 5,
    "Name": "Initech"
  }
}

理想-完全错过了合同解决者。我将jsonconverter作为修改给定类型序列化的唯一方法。非常感谢,没问题。很高兴我能帮上忙。啊,真希望我几个小时前看到这个。顺便问一下,你知道如何扭转这个过程吗?反序列化时转换器也存在同样的问题(它们实际上从流程中删除了newtonsoft),反序列化中不使用契约解析器。我希望(并且仍在寻找)api中的某个点,json.net会问我“这是一个JsonObject,给我它所需的类型和属性设置器”。到目前为止,我所看到的只是使用泛型反序列化,然后自己解析出对象图,它是meh。@将使用自定义SerializationBinder,请参阅
{
  "MyTypeName": "Person",
  "Id": 2,
  "Name": "Peter",
  "Employer": {
    "MyTypeName": "Company",
    "Id": 5,
    "Name": "Initech"
  }
}