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

C#如何将Lane类中两个相似判定方法重构为可复用泛型方法

解决方案

方案1:委托抽离差异化逻辑(推荐,改动最小)

直接把接口转换、判定方法调用这两处唯一的差异点通过Lambda委托传入通用方法,完全不需要修改现有接口、音符类的实现,无额外性能损耗:

public class Lane {
    // 提取公共逻辑的通用方法
    private bool CheckKeyCommon(Func<MusicNoteGameObject, Judgement> judgeFunc, double inputBeat) {
        MusicNoteGameObject frontNote = visibleNotes.Peek();
        Judgement j = judgeFunc(frontNote);
        // 此处放原来两份完全相同的剩余逻辑
    }

    // 原按键按下方法仅保留差异化逻辑
    private bool CheckKeyDown(double inputBeat) {
        return CheckKeyCommon(note => ((IJudgeDown)note).JudgeDown(inputBeat), inputBeat);
    }

    // 原按键抬起方法仅保留差异化逻辑
    private bool CheckKeyUp(double inputBeat) {
        return CheckKeyCommon(note => ((IJudgeUp)note).JudgeUp(inputBeat), inputBeat);
    }
}

方案2:泛型实现(满足泛型函数需求)

如果希望用泛型约束来规范传入的判定接口,可以用如下实现,编译期即可完成类型校验,不需要反射:

public class Lane {
    // 泛型通用判定方法
    private bool Judge<T>(Func<T, double, Judgement> judgeMethod, double inputBeat) {
        MusicNoteGameObject frontNote = visibleNotes.Peek();
        // 先转object再转泛型即可避免直接转换报错
        T judgeObj = (T)(object)frontNote;
        Judgement j = judgeMethod(judgeObj, inputBeat);
        // 此处放原来两份完全相同的剩余逻辑
    }

    private bool CheckKeyDown(double inputBeat) {
        return Judge<IJudgeDown>((obj, beat) => obj.JudgeDown(beat), inputBeat);
    }

    private bool CheckKeyUp(double inputBeat) {
        return Judge<IJudgeUp>((obj, beat) => obj.JudgeUp(beat), inputBeat);
    }
}

方案3:重构接口设计(扩展性最优)

如果项目还在迭代前期,可以调整接口抽象,把判定时机作为参数传入,后续新增判定类型不需要额外新增接口:

// 判定时机枚举
public enum JudgeTiming
{
    KeyDown,
    KeyUp
}

// 统一判定接口
public interface IJudgable {
    public Judgement Judge(JudgeTiming timing, double inputBeat);
}

// 音符类实现示例
public class TapNoteGameObject : MusicNoteGameObject, IJudgable {
    public Judgement Judge(JudgeTiming timing, double inputBeat) {
        return timing switch
        {
            JudgeTiming.KeyDown => JudgeDown(inputBeat),
            JudgeTiming.KeyUp => JudgeUp(inputBeat),
            _ => Judgement.Miss
        };
    }
    // 原有JudgeDown、JudgeUp内部实现保留
}

// Lane类仅需一个通用判定方法
public class Lane {
    private bool CheckKey(JudgeTiming timing, double inputBeat) {
        MusicNoteGameObject frontNote = visibleNotes.Peek();
        IJudgable judgable = (IJudgable)frontNote;
        Judgement j = judgable.Judge(timing, inputBeat);
        // 公共逻辑
    }
}

注意事项

所有方案建议在类型转换前增加合法性校验,例如if (frontNote is IJudgeDown downObj),避免未实现对应接口的音符类型抛出强制转换异常,可根据业务逻辑处理异常场景(例如直接返回判定失败、打印错误日志等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 05:36:00