(此问题源于试图将LikeType类序列化/反序列化为JSON-https://github.com/kleinwareio/LikeType)
我有:
public abstract class LikeType<T>
{
public T Value;
// ....
// how to tell json.net to serialize/deserialize classes deriving
// from this like it would T ???
}
public class Name : LikeType<string> {
public Name(string s) : base(s) { }
// does not add any properties
}
void test()
{
var name = new Name("john");
var jobj = new JObject();
try
{
jobj.Add("key", new JObject(name));
}
catch (Exception e)
{
!Exeption !
e = {System.ArgumentException: Could not determine JSON object type for type Name. at Newtonsoft.Json.Linq.JValue.GetValueType(Nullable`1 current, Object value) at Newtonsoft.Json.Linq.JContainer.CreateFromContent(Object content)
}
}
我如何指定所有从LikeType<T>
派生的类都将以T
相同的方式通过Json.Net序列化/反序列化为JSON?
(在这种情况下,Json.Net应该以与字符串相同的方式对Name进行序列化/反序列化)
答案 0 :(得分:1)
我相信您想“转发” LikeType<T>
序列化,将其视为不可见的包装器类型。这个假设对我的解决方案至关重要。
我建议使用JsonConverter
实现。这里有一个非常相似的帖子:Json.NET - Serialize generic type wrapper without property name
我已根据您的情况调整了示例。这是适应的方法:
class LikeTypeConverter : JsonConverter
{
static Type GetValueType(Type objectType)
{
return objectType
.BaseTypesAndSelf()
.Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(LikeType<>))
.Select(t => t.GetGenericArguments()[0])
.FirstOrDefault();
}
public override bool CanConvert(Type objectType)
{
return GetValueType(objectType) != null;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// You need to decide whether a null JSON token results in a null LikeType<T> or
// an allocated LikeType<T> with a null Value.
if (reader.SkipComments().TokenType == JsonToken.Null)
return null;
var valueType = GetValueType(objectType);
var value = serializer.Deserialize(reader, valueType);
// Here we assume that every subclass of LikeType<T> has a constructor with a single argument, of type T.
return Activator.CreateInstance(objectType, value);
}
const string ValuePropertyName = "Value";// nameof(LikeType<object>.Value); // in C#6+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());
var valueProperty = contract.Properties.Single(p => p.UnderlyingName == ValuePropertyName);
serializer.Serialize(writer, valueProperty.ValueProvider.GetValue(value));
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
{
}
return reader;
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
如果要将其包含在库中,可以将其用作LikeType<T>
声明中的属性:
[JsonConverter(typeof(LikeTypeConverter))]
public abstract class LikeType<T> { ... }
或者您可以在必要时使用转换器,修改JsonSerializerSettings.Converters
集合:
var settings = new JsonSerializerSettings
{
Converters = { new LikeTypeConverter() },
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var result = JsonConvert.SerializeObject(myObject, Formatting.Indented, settings);
我还创建了一个working dotnetfiddle sample进行演示(也改编自链接文章)。
答案 1 :(得分:0)
控制大多数序列化程序进行序列化的一种方法是使用Serializable attribute并实现ISerializable interface。