泛型与可为空引用类型场景下的API设计方案咨询
泛型与可为空引用类型的API设计建议
不推荐带returnNullOn404参数的方案
带布尔参数的设计存在以下问题:
- 语义模糊:同一个方法承担两种不同职责(必返回有效值/可能返回null),违反单一职责原则,增加理解成本。
- 类型不安全:返回值的可空性无法通过类型系统明确表达,编译器无法提供静态检查,调用者容易因疏忽引发
NullReferenceException。
推荐拆分方法的方案(你当前考虑的方向)
拆分Get和GetOrDefault是更符合.NET设计惯例的做法,可进一步优化:
1. 移除引用类型约束,兼容值类型
无需限制T为引用类型,利用T?同时支持引用类型和值类型:
public class Demo<T> { public T Get(int id) { // 远程调用,404时抛出NotFoundException等异常 // 确保返回非null的引用类型实例或有效值类型 } public T? GetOrDefault(int id) { try { return Get(id); } catch (NotFoundException) { return default; } } }
该设计的核心优势:
- 语义清晰:
Get明确表示"找不到则抛异常",GetOrDefault表示"找不到返回默认值",调用者一目了然。 - 类型安全:编译器会根据
T的类型自动校验可空性,调用GetOrDefault后会提示可能为null,避免意外空引用。
2. 补充XML注释强化语义
为方法添加清晰注释,明确异常和返回值规则:
/// <summary> /// 根据ID获取指定项,找不到时抛出异常 /// </summary> /// <param name="id">目标项的ID</param> /// <returns>非null的T实例</returns> /// <exception cref="NotFoundException">远程返回404时抛出</exception> public T Get(int id) { // 实现逻辑 } /// <summary> /// 根据ID获取指定项,找不到时返回默认值 /// </summary> /// <param name="id">目标项的ID</param> /// <returns>找到则返回T实例,找不到返回null(引用类型)或default(T)(值类型)</returns> public T? GetOrDefault(int id) { // 实现逻辑 }
3. 遵循.NET类库设计惯例
这种拆分方式和Dictionary<TKey, TValue>的TryGetValue、List<T>的Find/FindOrDefault等内置方法思路一致,降低调用者的学习成本。
额外建议:引入TryGet模式
若需明确判断是否找到目标项,可补充TryGet方法,适合404场景频繁的情况(避免异常捕获的性能开销):
public bool TryGet(int id, out T? result) { try { result = Get(id); return true; } catch (NotFoundException) { result = default; return false; } }
内容的提问来源于stack exchange,提问作者Luis Abreu
相关产品推荐
相关产品推荐

