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

单个类多构造函数问题:UserKeys类第二个构造函数未被主类识别

解决C#构造函数重载被主类无法识别的问题

先把你的代码格式化一下,方便分析:

abstract class BaseKeys 
{ 
    public abstract bool LeftPressed(); 
    public abstract bool RightPressed(); 
    public abstract bool UpPressed(); 
    public abstract bool DownPressed(); 
    public abstract bool HighHitPressed(); // 建议统一PascalCase命名规范
    public abstract bool RopeJumpPressed(); 
    public abstract bool RunRightPressed(); 
    public abstract bool LeftRightPressed(); // 这里你写了override,应该是abstract吧?
} 

class UserKeys : BaseKeys 
{ 
    #region data 
    Keys left, right, up, down, walk; 
    Keys combo, high_hit; 
    #endregion 

    #region ctor 
    public UserKeys(Keys left, Keys right, Keys up, Keys down, Keys high_hit) 
    { 
        this.left = left; 
        this.right = right; 
        this.up = up; 
        this.down = down; 
        this.high_hit = high_hit; 
    } 

    public UserKeys(Keys right, Keys left, Keys down, Keys walk, Keys high_hit) 
    { 
        this.left = left; 
        this.right = right; 
        this.down = down; 
        this.high_hit = high_hit; 
        this.walk = walk; 
    } 
    #endregion

    // 这里需要实现BaseKeys的所有抽象方法,你代码里没写,不过这是另外的问题
}

你遇到的问题核心是构造函数重载的歧义:两个构造函数都接受5个Keys类型的参数,只是顺序和含义不同。当主类尝试实例化UserKeys时,如果只是按位置传递参数,编译器(或者你用的实例化逻辑,比如反射、DI容器)没办法区分你想调用哪一个,只会匹配第一个符合参数数量的构造函数,导致第二个构造函数看起来“不被识别”。

下面给你几个实用的解决办法:

1. 用命名参数明确指定构造函数

在实例化UserKeys的时候,通过命名参数告诉编译器你要调用哪个构造函数,这样就不会有歧义了。比如调用第二个带walk键的构造函数:

// 明确指定每个参数对应的构造函数参数名
var walkableUserKeys = new UserKeys(
    right: Keys.D, 
    left: Keys.A, 
    down: Keys.S, 
    walk: Keys.LeftShift, 
    high_hit: Keys.Space
);

这种方式简单直接,不需要修改类的结构,适合快速解决问题。

2. 用静态工厂方法替代重载构造函数

把第二个构造函数改成静态工厂方法,语义更清晰,还能避免构造函数重载的混乱。比如:

class UserKeys : BaseKeys 
{ 
    // ... 保留原有的字段和第一个构造函数 ...

    // 把第二个构造函数改成工厂方法
    public static UserKeys CreateWithWalkControl(Keys right, Keys left, Keys down, Keys walk, Keys highHit)
    {
        var keys = new UserKeys(); // 可以先加一个私有无参构造函数,或者调整逻辑
        keys.left = left;
        keys.right = right;
        keys.down = down;
        keys.high_hit = highHit;
        keys.walk = walk;
        return keys;
    }

    // 私有无参构造函数,供工厂方法使用
    private UserKeys() {}
}

调用的时候就可以用:

var walkableUserKeys = UserKeys.CreateWithWalkControl(Keys.D, Keys.A, Keys.S, Keys.LeftShift, Keys.Space);

这种方式的好处是方法名本身就说明了用途,主类调用时一眼就能知道这是创建带walk键的用户配置,可读性更强。

3. 为不同角色创建子类(更符合OOP设计)

既然你是为每个角色创建对应的按键配置,不如直接为不同角色创建子类,每个子类对应自己的构造逻辑,这样主类可以直接依赖不同的子类,完全避免构造函数歧义:

// 普通角色的按键配置
class RegularUserKeys : UserKeys
{
    public RegularUserKeys(Keys left, Keys right, Keys up, Keys down, Keys highHit) 
        : base(left, right, up, down, highHit)
    {
    }
}

// 带walk键的角色按键配置
class WalkableUserKeys : UserKeys
{
    public WalkableUserKeys(Keys right, Keys left, Keys down, Keys walk, Keys highHit)
    {
        // 这里直接初始化字段
        this.left = left;
        this.right = right;
        this.down = down;
        this.high_hit = highHit;
        this.walk = walk;
    }
}

主类需要哪个角色的配置,就直接实例化对应的子类,逻辑更清晰,也方便后续扩展不同角色的特殊按键逻辑。

另外提个小建议:C#里方法和属性建议用PascalCase命名(比如HighHitPressed而不是high_hitPressed),字段用camelCase,这样符合.NET的命名规范,代码可读性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:00:45