我在C#中有一个类别的类,该类具有许多变量。我们称之为"QuestionItem"
。我有一个对象的列表,用户对其进行了修改,然后通过JSON Serialization(带有Newtonsoft JSON库)将其发送到服务器。为此,我可以将已经在服务器中的对象(作为List<QuestionItem>
)化,然后将此新的修改对象添加到列表中,然后将其序列化回服务器。
为了向用户显示此QuestionItems
的列表,我将JSON视为我的对象,并将其显示在某个地方。
现在,问题是 - 我想更改此QuestionItem
并在其中添加一些变量。
但我无法将此NewQuestionItem
发送到服务器,因为服务器中的项目是类型OldQuestionItem
。
如何合并这两种类型,或将旧类型转换为新类型,而具有旧版本的用户仍然可以使用该应用程序?
您使用的是面向对象的语言,因此您可以尽可能使用继承。
假设您的旧QuestionItem
为:
[JsonObject(MemberSerialization.OptOut)]
public class QuestionItem
{
[JsonConstructor]
public QuestionItem(int Id, int Variant)
{
this.Id = Id;
this.Variant = Variant;
}
public int Id { get; }
public int Variant { get; }
public string Name { get; set; }
}
您可以通过创建子类来扩展它:
[JsonObject(MemberSerialization.OptOut)]
public class NewQuestionItem : QuestionItem
{
private DateTime _firstAccess;
[JsonConstructor]
public NewQuestionItem(int Id, int Variant, DateTime FirstAccess) : base(Id, Variant)
{
this.FirstAccess = FirstAccess;
}
public DateTime FirstAccess { get; }
}
请注意,使用与类的默认构造函数不同的任何内容都需要您在此构造函数上使用[JsonConstructor]
属性,并且所述构造函数的每个参数必须与相应的JSON属性完全命名。否则,您会得到例外,因为没有默认构造函数。
您的WebAPI现在将发送序列化的NewQuestionItem
s,可以将其划分为QuestionItem
s。实际上:默认情况下,JSON.NET与大多数JSON库一样,如果它们具有共同的至少一个属性。只需确保您要序列化/排斥的对象的任何成员实际上都可以序列化即可。
您可以使用以下三行代码测试以上示例:
var newQuestionItem = new NewQuestionItem(1337, 42, DateTime.Now) {Name = "Hello World!"};
var jsonString = JsonConvert.SerializeObject(newQuestionItem);
var oldQuestionItem = JsonConvert.DeserializeObject<QuestionItem>(jsonString);
只是查看调试器中oldQuestionItem
的属性值。
因此,只要您的newQuestionItem仅将属性添加到对象中,并且既不删除也不修改它们。
如果是这种情况,那么您的对象是不同的,因此,只要您仍然需要,就需要需要完全不同的对象,而 在现有的URI上维护旧实例。
将我们带入一般体系结构:
最干净,最简化的方法是您要实现的目标是正确版本的API。
出于此链接的目的,我假设ASP.NET WebAPI,因为您正在处理C#/。Net中的JSON。这允许调用不同版本的不同控制器方法,因此,进行结构上的更改,您的API根据实现时间提供了您的API提供的资源。其他API将提供相等或至少类似的功能,否则可以手动实现。
取决于实际对象的数量和大小以及请求和结果集的潜在复杂性,也可能值得研究包装请求或响应附加信息。因此,您不必要求类型T
的对象,而是要求一个类型QueryResult<T>
的对象,其对象是按照以下方式定义的:
[JsonObject(MemberSerialization.OptOut)]
public class QueryResult<T>
{
[JsonConstructor]
public QueryResult(T Result, ResultState State,
Dictionary<string, string> AdditionalInformation)
{
this.Result = result;
this.State = state;
this.AdditionalInformation = AdditionalInformation;
}
public T Result { get; }
public ResultState State { get; }
public Dictionary<string, string> AdditionalInformation { get; }
}
public enum ResultState : byte
{
0 = Success,
1 = Obsolete,
2 = AuthenticationError,
4 = DatabaseError,
8 = ....
}
将允许您运送其他信息,例如API版本号,API版本发布,链接到不同的API端点,错误信息而不更改对象类型等。
将包装器与自定义标头一起使用的替代方法是完全实现Hateoas约束,这也被广泛使用。两者都可以与适当的版本控制一起为您节省API更改的大部分麻烦。
您将oldQuestionItem包裹为问题的属性怎么样?例如:
public class NewQuestionItem
{
public OldQuestionItem OldItem { get; set; }
public string Property1 {get; set; }
public string Property2 {get; set; }
...
}
这样,您可以维护该项目的先前版本,但定义要返回的新信息。
koda
您可以使用
之类的东西public class OldQuestionItem
{
public DateTime UploadTimeStamp {get; set;} //if less then DateTime.Now then it QuestionItem
public string Property1 {get; set; }
public string Property2 {get; set; }
...
public OldQuestionItem(NewQuestionItem newItem)
{
//logic to convert new in old
}
}
public class NewQuestionItem : OldQuestionItem
{
}
并用作uploadTimestamp作为标记,是什么问题。