我有一个类,DataPacket,它看起来像这样

public class DataPacket
{
    public DataPacket()
    {
    }

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

我有一个特定的数据包,名为SessionDataPacket,它继承自这个DataPacket类:

public class SessionDataPacket : DataPacket
{
    public string SessionId { get; set; }
    public string UserId { get; set; }

    public SessionDataPacket(string sessionId, string userId)
    {
        this.SessionId = sessionId;
        this.UserId = userId;
    }
}

我想添加一个名为FromJson的函数,该函数创建正确类的对象.我想出了一个泛型函数,如下所示:

 public static T FromJson<T>(string json) where T : DataPacket
 {
     return JsonConvert.DeserializeObject<T>(json);
 }

这是DataPacket中的一个函数,可用于指定我想要创建的DataPacket的类型.然而,这将不得不这样命名:

SessionDataPacket sessionData = DataPacket.FromJson<SessionDataPacket>(responseData);

我的问题是:有没有一种方法可以调用这个函数,而不必在泛型方法中指定它的类型,这样我就可以这样使用它:

SessionDataPacket sessionData = SessionDataPacket.FromJson(responseData);

推荐答案

最好不要try 这样做.有一些方法可以支持这一点,但通过try 支持这一点,您正在创建一种高度特定于您的运行时的新的、非标准的方法.

假设您要替换一行代码:

JsonConvert.DeserializeObject<SessionDataPacket>(json);

要以非泛型形式编写该代码,您仍然需要了解类型,因此没有实际的好处:

SessionDataPacket.FromJson(json);

没有什么能阻止你在具体类型中实现FromJson(string),但是大多数继承实现会导致将结果转换为它的基形式或实现一个接口.这是一个典型的过度封装的例子,随着时间的推移,你会想要避免.

通过包装一个标准库调用,让每个.NET开发人员都能理解您自己的定制专有实现,您真正获得了什么?这似乎有违常理,但这是负面工作的开始,因此也是技术性债务的开始.

围绕这一点有许多争论,但最终序列化属于类定义之外,除非您有真正特定的自定义序列化需求,即使这样,您也应该首先使用您想要用来更好地描述模型的序列化库的序列化属性.

一旦您开始鼓励您自己和您的开发人员使用您的定制实现,您会发现您的实现可能会发展,或者跟不上标准,以至于将来很难维护您的代码,或者您的开发人员将很难在没有定制convention的其他团队和项目中运行.

只要想想这里所涉及的工作,在有标准方法的情况下,您的方法通过使用更多的代码行来隐藏隐含的复杂性,那么我们并没有让事情变得更好.将类似FromJson的实现保留到类不符合标准或无法使用JSON.Net或System.Text.Json中的标准可扩展挂钩来表达反序列化逻辑的场景


在这个概念出现问题的场景中,或者当您开始寻找多态反序列化处理程序时,通常值得考虑使用composition而不是inheritance.在没有更多细节的情况下,很难深入到这里,但是假设你有3个类,它们都只有很小的细节不同,也许每个类都有一个其他类没有的属性……

您可以组成一个具有所有这三个属性(包括任何或所有公共属性)的新类型.

当我们反序列化到新类型时,我们可以忽略丢失的成员,这将为您提供一种类型安全的方法来管理您想要反序列化的每个模型.

为了更接近composition model,您为要实现的每个特定类型创建一个interface,使您的组合模型实现每个接口,现在您可以通过接口隐式强制转换模型.

这仍然可能是过度工程,但对于DTO和函数式编程来说,这通常是一种更灵活的方法,因为大多数业务逻辑都在具体类型之外.

Csharp相关问答推荐

如何打印已添加到List的Linq值,而不是C#中的:System.Collections.Generic.List ' 1[System.Int32]?

为什么使用DXGI输出复制和Direct 3D时捕获的图像数据全为零?

. NET 8 HttpClient post参数将其情况更改为camel'

有没有一种方法可以在包含混合文本的标签中嵌入超链接?

一种安全的方式来存储SSH凭证(MAUI/C#应用程序)

始终保留数组中的最后N个值,丢弃最老的

为什么在ANTLR4中会出现不匹配的输入错误?""

与C#中的Zip列表并行

模型绑定RazorPage表单

S能够用DATETIME来计算,这有什么错呢?

Polly重试URL复制值

try 链接被委派者(多播委托)时,无法将获取运算符应用于类型为';方法组&39;和方法组';的操作数

正在从最小API-InvocationConext.Arguments中检索参数的FromBodyAttribute

Xamarin.Forms-如何创建可 Select 的显示alert 或弹出窗口?

ASP.NET核心8:app.UseStaticFiles()管道执行顺序

无法使用直接URL通过PictureBox.ImageLocation加载图像

如何处理ASP.NET Core中包含两个构造函数的控制器?

测试单个对象是否与Func<;T,bool>;匹配

C#LINQ多行条件

是否在异步方法中避免Span<;T>;.ToArray()?