【问题标题】:How to add deserialize method to abstract class如何将反序列化方法添加到抽象类
【发布时间】:2019-03-18 08:21:20
【问题描述】:

我有一个想法,但我不明白怎么做。

我创建了一个abstract class AJsonSerializer。我想在那里 SerializeDeserialize 上课。

public abstract class AJsonSerializer {
  public string ToJson() {
    return JsonConvert.SerializeObject(this);
  }

  public T FromJson<T>(string jsonString) where T : class {
    return JsonConvert.DeserializeObject<T>(jsonString);
  }
}

我有一个类User,我继承自我的抽象类:

public class User : AJsonSerializer {
  public string PublicKey { get; set; }
  public int User_ID { get; set; }
}

现在我可以这样做了

internal static void Get_UserData(string username, ref User user) {
  if (ReadFromCache(username, out string value)) {
    user = user.FromJson<User>(value);
  } else {
    DataAccess.Get_UserData(username, out string user_public_key, out int id_user);

    user.PublicKey = user_public_key;
    user.User_ID = id_user;

    value = user.ToJson();

    SaveToCashe(username, value);
  }
}

这一行看起来很难看:user = user.FromJson&lt;User&gt;(value);

我想这样做:user.FromJson(value);

我知道如何在 User 类中做到这一点(下面的示例),但我想在抽象类中做到这一点,然后这个方法将适用于我的所有类

不好的方法如何解决它,只需将初始化器添加到类User,就像那里一样:

public User(string jsonString) {
  User user = JsonConvert.DeserializeObject<ApiUser>(jsonString);
  PublicKey = user.PublicKey;
  User_ID = user.User_ID;
}

【问题讨论】:

  • 不要这样做。这违反了 SRP。将序列化与模型分开 (User)。模型必须不知道如何序列化和存储它们。
  • 问题是:你为什么要这样做?为什么不直接使用JsonConvert.DeserializeObject?另一个丹尼斯也提出了一个很好的观点。
  • 我同意以前的 cmets。我看不出将序列化作为类本身的一部分有什么好处。在Get_UserData 中,只需直接调用JsonConvert.DeserializeObject
  • @DennisKuypers @Dennis 有趣的一点,但我只想在需要Deserialize 类的地方简化我的代码。然后在每个类中使用来自 json-string 的自定义反序列化器。在我可以将它用于测试而不是模拟类之后,我将存储一些 json-strings
  • @IgorCova 如果不同的类需要自定义序列化,您可以将JsonConverterAttribute 添加到类并指向特定的序列化类来处理这种情况。

标签: c# json .net-core


【解决方案1】:

类似于 Jerries 的答案,另一种选择只是一种扩展方法。您可以将 T 约束为 AJsonSerializer,使其仅限于它的子类型。您不能覆盖扩展方法,但在您的代码中,您一开始就没有将它作为虚拟方法。

public static class SerializerExtensions {
   public static T FromJson<T>(this T obj, string json) where T:AJsonSerializer  {
       JsonConvert.PopulateObject(json, obj);
       return obj;
   }
}

这样您就不需要在整个继承链中实现泛型类型的传递。 但是你需要初始化要访问的值,所以它是:

var user = new User();
user.FromJson(jsonSTring);

var user = SerializerExtensions.FromJson(new User(), jsonString);

由您决定什么更适合您的用例。

【讨论】:

  • 非常好的答案。这并不违反 SRP。 @Dennis 的注释
  • 但这没有任何意义。您创建一个用户对象,只需对其调用 en 扩展名即可将其替换为另一个实例。
  • @Magnus,说得好。我将其更改为 PopulateObject,所以现在它填充初始实例,而不是创建新实例。
  • PopulateObject之后我们也可以剪切return obj
  • 这取决于您的用例。你可以退货,如果你想分配和创建一条线,如果你不那样使用它,你可以剪掉它。
【解决方案2】:

你可以在你的类定义中声明泛型

public class User : AJsonSerializer<User>
{
    public string PublicKey { get; set; }
    public int User_ID { get; set; }
}
public abstract class AJsonSerializer<T>
    where T : class
{
    public string ToJson() {
        return JsonConvert.SerializeObject(this);
    }

    public static T FromJson(string jsonString) {
        return JsonConvert.DeserializeObject<T>(jsonString);
    }
}

编辑:正如卡拉在他的评论中所说,您的 FromJson 方法可以是静态的。所以你可以这样称呼它

var user = User.FromJson(jsonString);

【讨论】:

  • FromJson() 应该是 static。你不需要你的类的实例来反序列化。
  • 是的,我只是复制粘贴了op的代码,并没有真正看懂。
猜你喜欢
  • 2010-10-12
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
  • 2012-11-18
  • 1970-01-01
  • 2016-08-20
  • 2011-04-07
  • 1970-01-01
相关资源
最近更新 更多