使用 ServiceStack.Text 反序列化派生泛型类型时出错
Error using ServiceStack.Text to deserialize derived generic type
我在将对象存储到 Redis 之前使用 ServiceStack.Text 到 serialize/deserialize 对象,但是我遇到了一些对象,它们不会按预期反序列化。
我有一个基类型(一些遗留代码,许多项目都使用这个基类型)和一个 属性 类型的对象。后来添加了基本类型的通用版本,将 属性 公开为通用类型。
使用 ServiceStack.Text 序列化和反序列化泛型类型在基础 class(类型对象)上设置 属性,而不是在派生的 [=44= 上设置更具体的类型].
重现错误的简单控制台应用程序如下所示:
class Program
{
public class Base<T> : Base
{
//hide the Value property on the base class
public new T Value { get; set; }
}
public class Base
{
public object Value { get; set; }
}
static void Main(string[] args)
{
var a = new Base<List<string>>()
{
Value = new List<string>() { "one", "two", "three" },
};
var serialized = TypeSerializer.SerializeToString(a);
var deserialized = TypeSerializer.DeserializeFromString<Base<List<string>>>(serialized);
//throws a null ref exception
Console.WriteLine(deserialized.Value.Count);
}
}
反序列化后设置断点,Visual Studio显示base.Value的对象为List,其值为序列化列表,但我的Base上的值为属性 > class 为空。
Screenshot of debugger in Visual Studio
有什么方法可以配置 TypeSerializer(或 JsonSerializer)以正确设置为更具体的 属性 而不是基于 class 的 属性?
感谢任何帮助。
更新
根据答案,我通过使 Base<T>
和 Base
继承自新的抽象基础 class 来解决它,如下所示:
public abstract class DummyBase
{
public string Test { get; set; } = "Test";
}
public class BaseResponse<T> : DummyBase
{
public T Value { get; set; }
}
public class BaseResponse : DummyBase
{
public object Value { get; set; }
}
即使 Base.Value 被隐藏,反射仍然可见(例如 a.GetType().GetProperties()
。这可能是问题所在。
以下似乎可行。 Base<T>
中的 getter 和 setter 只是包裹了 Base.Value
。 DummyBase<T>
是让 ServiceStack 将字符串反序列化为正确类型所必需的。
class Program
{
public static void Main (string[] args)
{
var a = new Base<List<string>>()
{
Value = new List<string> { "one", "two", "three" },
};
var serialized = TypeSerializer.SerializeToString(a);
var deserialized = TypeSerializer.DeserializeFromString<DummyBase<List<string>>>(serialized);
// no longer throws a null ref exception
Console.WriteLine(deserialized.Value.Count);
}
}
public class DummyBase<T>
{
public T Value { get; set; }
}
public class Base<T> : Base
{
public new T Value
{
get { return (T)base.Value; }
set { base.Value = value; }
}
}
public class Base
{
public object Value { get; set; }
}
当然,如果 Base<T>
没有继承自 Base
,那么这一切都不是必需的。
我在将对象存储到 Redis 之前使用 ServiceStack.Text 到 serialize/deserialize 对象,但是我遇到了一些对象,它们不会按预期反序列化。
我有一个基类型(一些遗留代码,许多项目都使用这个基类型)和一个 属性 类型的对象。后来添加了基本类型的通用版本,将 属性 公开为通用类型。
使用 ServiceStack.Text 序列化和反序列化泛型类型在基础 class(类型对象)上设置 属性,而不是在派生的 [=44= 上设置更具体的类型].
重现错误的简单控制台应用程序如下所示:
class Program
{
public class Base<T> : Base
{
//hide the Value property on the base class
public new T Value { get; set; }
}
public class Base
{
public object Value { get; set; }
}
static void Main(string[] args)
{
var a = new Base<List<string>>()
{
Value = new List<string>() { "one", "two", "three" },
};
var serialized = TypeSerializer.SerializeToString(a);
var deserialized = TypeSerializer.DeserializeFromString<Base<List<string>>>(serialized);
//throws a null ref exception
Console.WriteLine(deserialized.Value.Count);
}
}
反序列化后设置断点,Visual Studio显示base.Value的对象为List> class 为空。
Screenshot of debugger in Visual Studio
有什么方法可以配置 TypeSerializer(或 JsonSerializer)以正确设置为更具体的 属性 而不是基于 class 的 属性?
感谢任何帮助。
更新
根据答案,我通过使 Base<T>
和 Base
继承自新的抽象基础 class 来解决它,如下所示:
public abstract class DummyBase
{
public string Test { get; set; } = "Test";
}
public class BaseResponse<T> : DummyBase
{
public T Value { get; set; }
}
public class BaseResponse : DummyBase
{
public object Value { get; set; }
}
即使 Base.Value 被隐藏,反射仍然可见(例如 a.GetType().GetProperties()
。这可能是问题所在。
以下似乎可行。 Base<T>
中的 getter 和 setter 只是包裹了 Base.Value
。 DummyBase<T>
是让 ServiceStack 将字符串反序列化为正确类型所必需的。
class Program
{
public static void Main (string[] args)
{
var a = new Base<List<string>>()
{
Value = new List<string> { "one", "two", "three" },
};
var serialized = TypeSerializer.SerializeToString(a);
var deserialized = TypeSerializer.DeserializeFromString<DummyBase<List<string>>>(serialized);
// no longer throws a null ref exception
Console.WriteLine(deserialized.Value.Count);
}
}
public class DummyBase<T>
{
public T Value { get; set; }
}
public class Base<T> : Base
{
public new T Value
{
get { return (T)base.Value; }
set { base.Value = value; }
}
}
public class Base
{
public object Value { get; set; }
}
当然,如果 Base<T>
没有继承自 Base
,那么这一切都不是必需的。