- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我需要将我的类转换为 JSON,我使用 Json.NET。但我可以有不同的 JSON 结构,例如:
{
name: "Name",
type: "simple1",
value: 100
};
或
{
name: "Name",
type: {
optional1: {
setting1: "s1",
setting2: "s2",
///etc.
},
value: 100
};
我的 C# 代码是:
public class Configuration
{
[JsonProperty(PropertyName = "name")]
public string Name{ get; set; }
[JsonProperty(PropertyName = "type")]
public MyEnumTypes Type { get; set; }
public OptionalType TypeAdditionalData { get; set; }
[JsonProperty(PropertyName = "value")]
public int Value { get; set; }
public bool ShouldSerializeType()
{
OptionalSettingsAttribute optionalSettingsAttr = this.Type.GetAttributeOfType<OptionalSettingsAttribute>();
return optionalSettingsAttr == null;
}
public bool ShouldSerializeTypeAdditionalData()
{
OptionalSettingsAttribute optionalSettingsAttr = this.Type.GetAttributeOfType<OptionalSettingsAttribute>();
return optionalSettingsAttr != null;
}
}
public enum MyEnumTypes
{
[EnumMember(Value = "simple1")]
Simple1,
[EnumMember(Value = "simple2")]
Simple2,
[OptionalSettingsAttribute]
[EnumMember(Value = "optional1")]
Optional1,
[EnumMember(Value = "optional2")]
[OptionalSettingsAttribute]
Optional2
}
我的想法是当 Configuration.Type
- 值没有属性 OptionalSettingsAttribute
- 将其序列化为 type: "simple1"
。否则 - 使用 Configuration.Type
- 值作为类型的值键(type: { optional1: {} }
)和 Configuration.TypeAdditionalData
中的值作为 optional1
- 值(如上面的 2 个简单 JSON)。
我尝试创建一个自定义转换器,例如:
public class ConfigurationCustomConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Configuration).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<Configuration>(reader);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//my changes here
serializer.Serialize(writer, value);
}
但是当我将 [JsonConverter(typeof(ConfigurationCustomConverter))]
属性添加到 Configuration
类时:
[JsonConverter(typeof(ConfigurationCustomConverter))]
public class Configuration
并调用了 JsonConvert.SerializeObject(configurationObj);
我收到了下一个错误:
Self referencing loop detected with type 'Configuration'. Path ''.
您是否知道如何更改我的代码以将我的类序列化为 2 种不同的 JSON 结构?注意:我不会使用相同的类来反序列化 JSON。
谢谢!
最佳答案
您收到检测到自引用循环
异常的原因是 WriteJson
转换器的方法正在递归调用自身。当您使用 [JsonConverter(typeof(ConfigurationCustomConverter))]
将转换器应用于类型时,WriteJson()
方法将无条件地替换 Json。 NET 的默认实现。因此你的内心呼唤:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//my changes here
serializer.Serialize(writer, value);
}
会导致堆栈溢出。 Json.NET 注意到这一点,而是抛出您看到的异常。有关详细信息,请参阅 JSON.Net throws StackOverflowException when using [JsonConvert()] .设置 ReferenceLoopHandling.Ignore
只会导致无限递归被跳过,使您的对象为空。
您有几个选项可以解决这个问题:
您可以手动编写除 Type
和 TypeAdditionalData
之外的所有属性名称和值,然后写出自定义 “type”
属性最后的。例如:
[JsonConverter(typeof(ConfigurationConverter))]
public class Configuration
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
public MyEnumTypes Type { get; set; }
public OptionalType TypeAdditionalData { get; set; }
[JsonProperty(PropertyName = "value")]
public int Value { get; set; }
}
class ConfigurationConverter : JsonConverter
{
const string typeName = "type";
public override bool CanConvert(Type objectType)
{
return typeof(Configuration).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var config = (existingValue as Configuration ?? (Configuration)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
// Populate the regular property values.
var obj = JObject.Load(reader);
var type = obj.RemoveProperty(typeName);
using (var subReader = obj.CreateReader())
serializer.Populate(subReader, config);
// Populate Type and OptionalType
if (type is JValue) // Primitive value
{
config.Type = type.ToObject<MyEnumTypes>(serializer);
}
else
{
var dictionary = type.ToObject<Dictionary<MyEnumTypes, OptionalType>>(serializer);
if (dictionary.Count > 0)
{
config.Type = dictionary.Keys.First();
config.TypeAdditionalData = dictionary.Values.First();
}
}
return config;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var config = (Configuration)value;
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(config.GetType());
writer.WriteStartObject();
foreach (var property in contract.Properties
.Where(p => p.Writable && (p.ShouldSerialize == null || p.ShouldSerialize(config)) && !p.Ignored))
{
if (property.UnderlyingName == "Type" || property.UnderlyingName == "TypeAdditionalData")
continue;
var propertyValue = property.ValueProvider.GetValue(config);
if (propertyValue == null && serializer.NullValueHandling == NullValueHandling.Ignore)
continue;
writer.WritePropertyName(property.PropertyName);
serializer.Serialize(writer, propertyValue);
}
writer.WritePropertyName(typeName);
if (config.Type.GetCustomAttributeOfEnum<OptionalSettingsAttribute>() == null)
{
serializer.Serialize(writer, config.Type);
}
else
{
var dictionary = new Dictionary<MyEnumTypes, OptionalType>
{
{ config.Type, config.TypeAdditionalData },
};
serializer.Serialize(writer, dictionary);
}
writer.WriteEndObject();
}
}
public class OptionalType
{
public string setting1 { get; set; }
}
public class OptionalSettingsAttribute : System.Attribute
{
public OptionalSettingsAttribute()
{
}
}
[JsonConverter(typeof(StringEnumConverter))]
public enum MyEnumTypes
{
[EnumMember(Value = "simple1")]
Simple1,
[EnumMember(Value = "simple2")]
Simple2,
[OptionalSettingsAttribute]
[EnumMember(Value = "optional1")]
Optional1,
[EnumMember(Value = "optional2")]
[OptionalSettingsAttribute]
Optional2
}
public static class EnumExtensions
{
public static TAttribute GetCustomAttributeOfEnum<TAttribute>(this Enum value)
where TAttribute : System.Attribute
{
var type = value.GetType();
var memInfo = type.GetMember(value.ToString());
return memInfo[0].GetCustomAttribute<TAttribute>();
}
}
public static class JsonExtensions
{
public static JToken RemoveProperty(this JObject obj, string name)
{
if (obj == null)
return null;
var property = obj.Property(name);
if (property == null)
return null;
var value = property.Value;
property.Remove();
property.Value = null;
return value;
}
}
请注意,我将 [JsonConverter(typeof(StringEnumConverter))]
添加到您的枚举中。这确保类型始终写为字符串。
样本 fiddle .
您可以通过 JSON.Net throws StackOverflowException when using [JsonConvert()] 中所示的技术禁用对转换器的递归调用。 ,生成一个默认的序列化,根据需要修改,写出来。
您可以通过将 Type
和 TypeAdditionalData
标记为 [JsonIgnore]
并引入额外的私有(private)来完全避免使用转换器序列化和反序列化 "type"
的属性:
public class Configuration
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonIgnore]
public MyEnumTypes Type { get; set; }
[JsonIgnore]
public OptionalType TypeAdditionalData { get; set; }
[JsonProperty("type")]
JToken SerializedType
{
get
{
if (Type.GetCustomAttributeOfEnum<OptionalSettingsAttribute>() == null)
{
return JToken.FromObject(Type);
}
else
{
var dictionary = new Dictionary<MyEnumTypes, OptionalType>
{
{ Type, TypeAdditionalData },
};
return JToken.FromObject(dictionary);
}
}
set
{
if (value == null || value.Type == JTokenType.Null)
{
TypeAdditionalData = null;
Type = default(MyEnumTypes);
}
else if (value is JValue)
{
Type = value.ToObject<MyEnumTypes>();
}
else
{
var dictionary = value.ToObject<Dictionary<MyEnumTypes, OptionalType>>();
if (dictionary.Count > 0)
{
Type = dictionary.Keys.First();
TypeAdditionalData = dictionary.Values.First();
}
}
}
}
[JsonProperty(PropertyName = "value")]
public int Value { get; set; }
}
关于c# - Json.NET不同的json结构,基于枚举值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37896661/
我目前正在尝试基于哈希表构建字典。逻辑是:有一个名为 HashTable 的结构,其中包含以下内容: HashFunc HashFunc; PrintFunc PrintEntry; CompareF
如果我有一个指向结构/对象的指针,并且该结构/对象包含另外两个指向其他对象的指针,并且我想删除“包含这两个指针的对象而不破坏它所持有的指针”——我该怎么做这样做吗? 指向对象 A 的指针(包含指向对象
像这样的代码 package main import "fmt" type Hello struct { ID int Raw string } type World []*Hell
我有一个采用以下格式的 CSV: Module, Topic, Sub-topic 它需要能够导入到具有以下格式的 MySQL 数据库中: CREATE TABLE `modules` ( `id
通常我使用类似的东西 copy((uint8_t*)&POD, (uint8_t*)(&POD + 1 ), back_inserter(rawData)); copy((uint8_t*)&PODV
错误 : 联合只能在具有兼容列类型的表上执行。 结构(层:字符串,skyward_number:字符串,skyward_points:字符串)<> 结构(skyward_number:字符串,层:字符
我有一个指向结构的指针数组,我正在尝试使用它们进行 while 循环。我对如何准确初始化它并不完全有信心,但我一直这样做: Entry *newEntry = malloc(sizeof(Entry)
我正在学习 C,我的问题可能很愚蠢,但我很困惑。在这样的函数中: int afunction(somevariables) { if (someconditions)
我现在正在做一项编程作业,我并没有真正完全掌握链接,因为我们还没有涉及它。但是我觉得我需要它来做我想做的事情,因为数组还不够 我创建了一个结构,如下 struct node { float coef;
给定以下代码片段: #include #include #define MAX_SIZE 15 typedef struct{ int touchdowns; int intercepti
struct contact list[3]; int checknullarray() { for(int x=0;x<10;x++) { if(strlen(con
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Empty “for” loop in Facebook ajax what does AJAX call
我刚刚在反射器中浏览了一个文件,并在结构构造函数中看到了这个: this = new Binder.SyntaxNodeOrToken(); 我以前从未见过该术语。有人能解释一下这个赋值在 C# 中的
我经常使用字符串常量,例如: DICT_KEY1 = 'DICT_KEY1' DICT_KEY2 = 'DICT_KEY2' ... 很多时候我不介意实际的文字是什么,只要它们是独一无二的并且对人类读
我是 C 的新手,我不明白为什么下面的代码不起作用: typedef struct{ uint8_t a; uint8_t* b; } test_struct; test_struct
您能否制作一个行为类似于内置类之一的结构,您可以在其中直接分配值而无需调用属性? 前任: RoundedDouble count; count = 5; 而不是使用 RoundedDouble cou
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
在创建嵌套列表时,我认为 R 具有对列表元素有用的命名结构。我有一个列表列表,并希望应用包含在任何列表中的每个向量的函数。 lapply这样做但随后剥离了列表的命名结构。我该怎么办 lapply嵌套列
我正在做一个用于学习目的的个人组织者,我从来没有使用过 XML,所以我不确定我的解决方案是否是最好的。这是我附带的 XML 文件的基本结构:
我是新来的 nosql概念,所以当我开始学习时 PouchDB ,我找到了这个转换表。我的困惑是,如何PouchDB如果可以说我有多个表,是否意味着我需要创建多个数据库?因为根据我在 pouchdb
我是一名优秀的程序员,十分优秀!