You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

扩展ServiceRes<T>派生类:如何实现映射复用与实例返回?

针对ServiceRes派生扩展的解决方案

1. 复用ServiceRes方法并返回派生类实例

要复用Success这类基类方法同时返回ServiceResExt<T>实例,推荐给基类方法增加泛型自约束,让方法支持返回任意派生自当前基类的类型:

public class ServiceRes<T>
{
    protected internal ServiceRes() { } // 保留原有构造修饰符

    // 泛型方法,约束TResult必须派生自ServiceRes<T>且有无参构造
    public TResult Success<TResult>(T data) where TResult : ServiceRes<T>, new()
    {
        var result = new TResult();
        // 复用基类原有逻辑设置公共属性
        result.Data = data;
        result.Code = 200;
        result.Message = "操作成功";
        return result;
    }

    // 兼容原有调用的备选方案:给派生类写扩展方法
    public static ServiceResExt<T> AsExt(this ServiceRes<T> baseRes)
    {
        var extResult = new ServiceResExt<T>();
        // 复制基类属性
        extResult.Data = baseRes.Data;
        extResult.Code = baseRes.Code;
        extResult.Message = baseRes.Message;
        // 设置派生类专属属性
        extResult.TraceId = Guid.NewGuid().ToString();
        return extResult;
    }
}

// 派生类示例
public class ServiceResExt<T> : ServiceRes<T>
{
    public string TraceId { get; set; } // 专属属性
}

调用方式示例:

// 方式1:直接调用带泛型约束的基类方法
var extResult = new ServiceRes<T>().Success<ServiceResExt<T>>(data);

// 方式2:基于原有基类实例转换
var baseResult = ServiceRes<T>.Success(data);
var extResult = baseResult.AsExt();

2. 将派生类映射逻辑统一放在ServiceRes中

完全可以实现,推荐两种实用方案:

方案1:预留虚方法扩展点

在基类中定义虚方法,派生类重写专属属性的映射逻辑,基类方法统一触发这些逻辑:

public class ServiceRes<T>
{
    protected internal ServiceRes() { }

    // 基类预留的派生类映射入口
    protected virtual void MapDerivedProps() { }

    public TResult MapFrom<TResult>(T source) where TResult : ServiceRes<T>, new()
    {
        var result = new TResult();
        // 基类统一映射逻辑
        result.Data = source;
        result.Code = 200;
        // 触发派生类专属映射
        result.MapDerivedProps();
        return result;
    }
}

public class ServiceResExt<T> : ServiceRes<T>
{
    public string TraceId { get; set; }

    protected override void MapDerivedProps()
    {
        // 派生类专属属性映射逻辑
        TraceId = Guid.NewGuid().ToString();
    }
}

方案2:传入映射委托

基类方法接受一个设置派生类属性的委托,无需修改派生类即可完成统一映射:

public class ServiceRes<T>
{
    protected internal ServiceRes() { }

    public TResult MapFrom<TResult>(T source, Action<TResult> setDerivedProps) where TResult : ServiceRes<T>, new()
    {
        var result = new TResult();
        // 基类统一映射逻辑
        result.Data = source;
        result.Code = 200;
        // 执行派生类专属属性设置
        setDerivedProps(result);
        return result;
    }
}

// 调用时直接传入专属属性设置逻辑
var extResult = ServiceRes<T>.MapFrom<ServiceResExt<T>>(data, res => 
{
    res.TraceId = Guid.NewGuid().ToString();
    res.ExtraInfo = "自定义扩展内容";
});

3. 保持构造protected internal时,ServiceRes能否返回派生类实例?

可以实现。protected internal修饰的构造函数允许同一程序集内的所有类以及跨程序集的派生类访问,所以只要ServiceResExt<T>是ServiceRes<T>的派生类,基类可以通过两种方式创建派生类实例:

  1. 泛型约束new():如果派生类有无参构造(public/internal均可),基类的泛型方法可以直接new TResult()创建实例——因为TResult被约束为ServiceRes<T>,派生类能够访问基类的protected internal构造。

  2. 反射创建:如果派生类没有无参构造,基类可以通过反射调用派生类的构造函数(只要派生类构造能合法访问基类构造):

public TResult CreateDerivedInstance<TResult>() where TResult : ServiceRes<T>
{
    // 获取派生类的无参构造(支持非public构造)
    var constructor = typeof(TResult).GetConstructor(
        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, 
        Type.EmptyTypes
    );
    return (TResult)constructor.Invoke(null);
}

这种方式完全符合“禁止手动实例化基类”的要求——外部无法直接new ServiceRes<T>(),只能通过基类提供的方法获取派生类实例。


内容的提问来源于stack exchange,提问作者Aleks Vujic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:17:42