首页 > 解决方案 > 通过从 C# 中的泛型类派生来创建类型别名

问题描述

我有一个带有一些通用参数的类,在它使用的十几个类中输入这些参数很痛苦。

public abstract class StateBase<StatesList, StateData>
    where StatesList : class
    where StateData : class
{
    public string Name { get; protected set; }
    protected StatesList stateList;
    protected StateData stateData;

    public StateBase(StatesList stateList, StateData stateData)
    {
        Name = this.GetType().Name;
        this.stateList = stateList;
        this.stateData = stateData;
    }

    public abstract bool CanTransitionTo(StateBase<StatesList, StateData> newState);
    public abstract void Enter();
    public abstract StateBase<StatesList, StateData> Tick();
    public abstract void Exit();
}

我熟悉 C/C++ 的 typedef 特性,现在很想念它。我知道 C# 最接近的特性是“使用”指令,它允许您将别名限定为单个文件。我可能会回到那个失败的地方,但是现在,这些课程不断变化,我想要一些更火的东西,然后忘记。

因此,我尝试通过创建一个派生自上述类并填充了所有泛型参数的新类来更优雅地解决别名问题。

public abstract class AIState : StateMachine.StateBase<UnitAIStateList, AIStateData>
{
    public abstract override bool CanTransitionTo(AIState newState);
    public abstract override void Enter();
    public abstract override void Exit();
    public abstract override new AIState Tick();
}

你可以猜到,C# 并没有让我那么容易就摆脱它。基类'Tick()返回通用版本。我的派生类替换为实际类型。看起来它应该可以工作,因为 AIState 是它所要求的一种类型:

'AIState.Tick()': return type must be 'StateBase<UnitAIStateList, AIStateData>' to match overridden member 'StateBase<UnitAIStateList, AIStateData>.Tick()'

我怀疑这个失败的原因是因为 C# 没有实现类型协变,这是我不太熟悉的一个特性。但是,事实上,我对它还不够熟悉,无法真正知道这是否是我的解释。

标签: c#genericsaliasderived-classtype-alias

解决方案


几件事;

1)我会考虑您选择要求您的方法提供StateBase<StatesList, StateData>类型结果。Tick您需要使用的绝对最小类型是什么?object就够了吗?

2)如果您确实需要“与类型相同”的返回值,那么您将不得不以循环方式使用泛型,如下所示:

public abstract class StateBase<StatesList, StateData, TChildType>
 where StatesList : class
 where StateData : class
 where TChildType : StateBase<StatesList, StateData, TChildType> //notice addition of TChildType
{
    public string Name { get; protected set; }
    protected StatesList stateList;
    protected StateData stateData;

    public StateBase(StatesList stateList, StateData stateData)
    {
        Name = this.GetType().Name;
        this.stateList = stateList;
        this.stateData = stateData;
    }

    public abstract bool CanTransitionTo(TChildType newState);
    public abstract void Enter();
    public abstract TChildType Tick();
    public abstract void Exit();
}

public class DerivedState : StateBase<string, string, DerivedState>
{
    ...
}

推荐阅读