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

C#中结构相同的A、B类如何重构重复的GernerateStuff方法

实现方案

核心思路是使用泛型方法+接口约束,不需要返回弱类型的接口实例,既能完全复用公共逻辑,又能保证返回强类型的A、B对象,不需要额外类型转换,完全满足不合并A、B两个独立类的约束。

前置准备

先定义语义明确的公共接口,让A、B类实现该接口即可:

public interface IStuffEntity
{
    string Stuff{ get; set; }
    DateTime Created { get; set; }
    DateTime Expires { get; set; }
}

public class A : IStuffEntity
{
    public string Stuff{ get; set; }
    public DateTime Created { get; set; }
    public DateTime Expires { get; set; }
}

public class B : IStuffEntity
{
    public string Stuff{ get; set; }
    public DateTime Created { get; set; }
    public DateTime Expires { get; set; }
}

注:原代码中接口命名IInterface过于宽泛,不符合C#命名规范,可根据实际场景替换为更有业务含义的名称,不影响核心逻辑。

核心通用方法实现

原代码标记了async但方法内部没有任何异步等待操作,属于多余标记,会产生编译警告,以下实现移除了不必要的async关键字,如果后续确实要加入异步IO等逻辑,再补回async/await即可。

public T GenerateStuff<T>(int expireDays = 15) where T : IStuffEntity, new()
{
    using var randomNumberGenerator = RandomNumberGenerator.Create();
    var randomBytes = new byte[64];
    var now = DateTime.UtcNow;
    randomNumberGenerator.GetBytes(randomBytes);
    
    return new T
    {
        Stuff = Convert.ToBase64String(randomBytes),
        Created = now,
        Expires = now.AddDays(expireDays)
    };
}

两个泛型约束的作用:

  • where T : IStuffEntity:保证传入的类型都拥有Stuff、Created、Expires三个属性可以直接赋值,不会出现编译错误
  • where T : new():保证传入的类型拥有无参构造函数,可以直接在方法内部创建实例,不需要额外传入构造逻辑

调用方式

调用时指定泛型类型即可,返回值为强类型,可直接使用:

  • 生成A类实例(使用默认15天有效期):A aInstance = GenerateStuff<A>();
  • 生成B类实例(指定10天有效期):B bInstance = GenerateStuff<B>(10);

兜底兼容方案

如果后续A、B类修改了定义,没有无参构造函数(比如新增了必须传入的初始化参数),可以改用传入工厂委托的方式实现,不需要new()约束:

public T GenerateStuff<T>(Func<T> instanceFactory, int expireDays = 15) where T : IStuffEntity
{
    if (instanceFactory == null) throw new ArgumentNullException(nameof(instanceFactory));
    
    using var randomNumberGenerator = RandomNumberGenerator.Create();
    var randomBytes = new byte[64];
    var now = DateTime.UtcNow;
    randomNumberGenerator.GetBytes(randomBytes);
    
    var instance = instanceFactory();
    instance.Stuff = Convert.ToBase64String(randomBytes);
    instance.Created = now;
    instance.Expires = now.AddDays(expireDays);
    
    return instance;
}

对应调用方式:

// 适配需要传入构造参数的场景
A aInstance = GenerateStuff(() => new A(/* 传入A类需要的初始化参数 */), 15);
B bInstance = GenerateStuff(() => new B(/* 传入B类需要的初始化参数 */), 10);

不推荐直接返回IInterface类型的原因

如果把方法返回值设为IInterface,调用方拿到结果后如果要访问A/B类独有的属性、方法,必须手动执行强制类型转换,既增加了冗余代码,又存在转换失败的运行时风险,泛型方案完全规避了这个问题,是这类场景的标准实现方式。

内容的提问来源于stack exchange,提问作者Sharif Mamun

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 12:06:15