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

C#中将派生泛型类作为派生类属性是否属于反模式?

解决方案

你要的效果可以通过**奇异递归模板模式(CRTP)**实现,这是C#中处理这类派生类与配套泛型类型绑定场景的标准方案,不属于反模式,也不需要更换整体设计思路。

第一步:修正接口定义

首先你现有代码存在两处笔误和可优化点:

  1. 两个参数类命名重复,第二个ObjectTypeA应为ObjectTypeB
  2. IObjectType<in T>的Foo方法参数没有用到泛型约束,浪费了逆变的类型安全能力,修正后代码如下:
// 业务对象基类,非泛型版本用于统一存储、传递
public abstract class BaseObject
{
    // 可放置所有业务对象共有的非泛型属性、方法
}

public interface IObjectType<in T> where T : BaseObject
{
    // 参数用泛型约束的T,替代原来的BaseObject,保证类型安全
    void Foo(T obj);
}

// 对应ObjectA的参数类
public class ObjectTypeA : IObjectType<ObjectA>
{
    public void Foo(ObjectA obj)
    {
        // ObjectA专属配置逻辑
    }
}

// 对应ObjectB的参数类
public class ObjectTypeB : IObjectType<ObjectB>
{
    public void Foo(ObjectB obj)
    {
        // ObjectB专属配置逻辑
    }
}

第二步:用CRTP定义泛型业务基类

给BaseObject增加泛型重载,约束泛型参数必须是当前派生类本身,直接在基层完成IObjectType属性的绑定:

public abstract class BaseObject<TSelf> : BaseObject where TSelf : BaseObject<TSelf>
{
    public IObjectType<TSelf> Type { get; private set; }

    public void SetType(IObjectType<TSelf> type)
    {
        Type = type;
    }
}

第三步:实现派生业务类

派生类只需要将自身作为泛型参数传入基类,即可自动获得对应类型的IObjectType属性,不需要重复编写属性、方法定义:

public class ObjectA : BaseObject<ObjectA>
{
    // 自动继承的Type属性为IObjectType<ObjectA>类型
    // 自动继承的SetType方法仅接受IObjectType<ObjectA>参数
}

public class ObjectB : BaseObject<ObjectB>
{
    // 自动继承的Type属性为IObjectType<ObjectB>类型
    // 自动继承的SetType方法仅接受IObjectType<ObjectB>参数
}

效果验证

var objA = new ObjectA();
objA.SetType(new ObjectTypeA()); // 编译通过,类型匹配
objA.SetType(new ObjectTypeB()); // 编译报错,类型不匹配,符合预期的类型约束
objA.Type.Foo(objA); // 直接调用Foo方法,不需要任何类型转换

如果你需要统一存放不同类型的业务对象,直接使用非泛型BaseObject作为集合元素类型即可:

List<BaseObject> allObjects = new List<BaseObject>();
allObjects.Add(objA);
allObjects.Add(new ObjectB());

内容的提问来源于stack exchange,提问作者Julzerino Szach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 14:06:03