如何实现无需指定泛型类型的DataPacket子类FromJson调用
问题描述
我定义了基类DataPacket:
public class DataPacket { public DataPacket() { } public string ToJson() { return JsonConvert.SerializeObject(this); } }
还有继承自它的子类SessionDataPacket:
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; } }
我在DataPacket中添加了泛型FromJson方法用于反序列化生成实例:
public static T FromJson<T>(string json) where T : DataPacket { return JsonConvert.DeserializeObject<T>(json); }
目前调用时必须显式指定泛型类型:
SessionDataPacket sessionData = DataPacket.FromJson<SessionDataPacket>(responseData);
请问能否实现无需指定泛型类型,直接通过子类调用,即:
SessionDataPacket sessionData = SessionDataPacket.FromJson(responseData);
解决方案
可以实现,以下是几种常用的可行方案:
方案一:子类添加静态转发方法(最直接)
在每个子类中新增一个静态FromJson方法,内部调用基类的泛型方法并指定当前子类类型:
public class SessionDataPacket : DataPacket { // 原有属性和构造函数代码... public static new SessionDataPacket FromJson(string json) { return DataPacket.FromJson<SessionDataPacket>(json); } }
这样就能直接通过SessionDataPacket.FromJson(responseData)调用,返回值自动匹配子类类型,无需显式声明泛型参数。
方案二:基类结合反射实现通用逻辑(减少重复代码)
如果子类数量较多,不想逐个编写转发方法,可以借助反射让基类自动识别调用者类型,再配合子类的简单转发:
首先修改基类,新增一个非泛型的内部方法:
public class DataPacket { // 原有构造函数和ToJson方法... // 保留原泛型方法供特殊场景使用 public static T FromJson<T>(string json) where T : DataPacket { return JsonConvert.DeserializeObject<T>(json); } // 新增内部方法,通过反射获取调用者类型 protected static DataPacket FromJsonInternal(string json) { var callerMethod = new StackTrace().GetFrame(1).GetMethod(); var targetType = callerMethod.DeclaringType; return (DataPacket)JsonConvert.DeserializeObject(json, targetType); } }
然后子类只需一行代码实现转发:
public class SessionDataPacket : DataPacket { // 原有属性和构造函数代码... public static new SessionDataPacket FromJson(string json) { return (SessionDataPacket)FromJsonInternal(json); } }
这种方式下,每个子类的转发代码高度一致,避免重复编写泛型参数指定逻辑。
方案三:利用C# 7.3+的this约束(语法糖方案)
如果项目使用C# 7.3或更高版本,可以通过泛型的this约束实现基类的通用静态方法,让子类直接继承并自动推断类型:
public class DataPacket { // 原有代码... public static T FromJson<T>(this T _, string json) where T : DataPacket { return JsonConvert.DeserializeObject<T>(json); } }
调用时可以通过default关键字触发类型推断:
SessionDataPacket sessionData = default(SessionDataPacket).FromJson(responseData);
不过这种调用方式不如前两种直观,适合对语法糖接受度较高的场景。
内容的提问来源于stack exchange,提问作者GeekPeek
相关产品推荐
相关产品推荐

