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

C# WinForm中如何通过循环动态访问类的HitN属性?

嘿,这个场景我太熟悉了——硬编码处理可变数量的HitBox简直是后期维护的噩梦!给你两个实用的解决思路,优先推荐第一种,完全符合C#的设计习惯:

方案一:重构类,用集合存储HitBox点(强烈推荐)

这是最优雅、最易维护的方式。把原来零散的Hit1、Hit2、Hit3属性改成一个集合,比如List<Point>或者Point[],这样不管HitBox数量怎么变,循环遍历就行。

首先修改你的类定义(替换成你实际的类名):

public class YourCustomClass
{
    public string Name { get; set; }
    // 其实可以直接用HitBoxes.Count替代NumberOfHitBoxes,或者保留做校验用
    public int NumberOfHitBoxes { get; set; }
    // 用集合存储所有HitBox的起点
    public List<Point> HitBoxes { get; set; } = new List<Point>();
    
    // 对应你的Input/Output点,也建议改成集合,比如:
    public List<Point> InputPoints { get; set; } = new List<Point>();
    public List<Point> OutputPoints { get; set; } = new List<Point>();
    public string Type { get; set; }
}

然后修改MouseMove事件的逻辑,直接循环集合:

picture.MouseMove += (sender, e) => { 
    var c = sender as PictureBox; 
    if (null == c) return; 
    bool h = false; 
    if (_dragging) { 
        c.Top = e.Y + c.Top - _yPos; 
        c.Left = e.X + c.Left - _xPos; 
    } else { 
        // 遍历所有HitBox
        for (int i = 0; i < p.HitBoxes.Count; i++)
        {
            Point hitPoint = p.HitBoxes[i];
            // 判断鼠标是否在当前HitBox范围内
            if (e.X > hitPoint.X && e.X < hitPoint.X + hitw && 
                e.Y > hitPoint.Y && e.Y < hitPoint.Y + hitw)
            {
                hitbox(c, hitPoint.X, hitPoint.Y, 8);
                h = true;
                tb.Text = p.Type;
                // 根据索引取对应的Input/Output点,这里根据你的业务调整
                // 比如前两个是Input,第三个是Output,那可以加个判断:
                hitok = i < 2 ? p.InputPoints[i] : p.OutputPoints[i - 2];
                // 找到匹配的就跳出循环,避免重复处理
                break;
            }
        }
    } 
    if (!h)
    {
        picture.Refresh();
        h = false;
        hitok = new Point(0,0);
    } 
};

为什么强烈推荐这个?因为集合就是为可变数量的元素设计的,代码可读性拉满,性能也比反射好,后期要加HitBox只需要往集合里加元素,完全不用改判断逻辑。

方案二:用反射动态访问属性(仅适合无法修改类的场景)

如果因为某些限制不能修改原来的类结构,那可以用反射来动态获取Hit1、Hit2这类命名规律的属性。不过这个方式缺点不少,谨慎使用。

修改后的MouseMove代码:

picture.MouseMove += (sender, e) => { 
    var c = sender as PictureBox; 
    if (null == c) return; 
    bool h = false; 
    if (_dragging) { 
        c.Top = e.Y + c.Top - _yPos; 
        c.Left = e.X + c.Left - _xPos; 
    } else { 
        // 从1循环到NumberOfHitBoxes
        for (int i = 1; i <= p.NumberOfHitBoxes; i++)
        {
            // 动态获取HitN属性
            var hitProp = p.GetType().GetProperty($"Hit{i}");
            if (hitProp == null) continue; // 防止属性不存在报错
            Point hitPoint = (Point)hitProp.GetValue(p);
            
            if (e.X > hitPoint.X && e.X < hitPoint.X + hitw && 
                e.Y > hitPoint.Y && e.Y < hitPoint.Y + hitw)
            {
                hitbox(c, hitPoint.X, hitPoint.Y, 8);
                h = true;
                tb.Text = p.Type;
                // 动态获取对应的Input/Output点,这里要匹配你的命名规则
                var targetProp = i switch
                {
                    1 => p.GetType().GetProperty("Input1Point"),
                    2 => p.GetType().GetProperty("Input2Point"),
                    3 => p.GetType().GetProperty("Output1Point"),
                    _ => null
                };
                if (targetProp != null)
                {
                    hitok = (Point)targetProp.GetValue(p);
                }
                break;
            }
        }
    } 
    if (!h)
    {
        picture.Refresh();
        h = false;
        hitok = new Point(0,0);
    } 
};

反射的问题:性能不如直接访问属性,代码可读性差,而且如果属性名改了,编译时不会报错,运行时才会出问题。所以除非万不得已,别用这个方法。

额外小建议

可以把“判断鼠标是否在HitBox内”的逻辑封装成一个单独的方法,代码更简洁:

private bool IsMouseInHitBox(Point mousePos, Point hitBoxOrigin, int hitBoxSize)
{
    return mousePos.X > hitBoxOrigin.X && 
           mousePos.X < hitBoxOrigin.X + hitBoxSize && 
           mousePos.Y > hitBoxOrigin.Y && 
           mousePos.Y < hitBoxOrigin.Y + hitBoxSize;
}

这样循环里只需要调用IsMouseInHitBox(e.Location, hitPoint, hitw)就行,后期要调整判断逻辑也只需要改这一个方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:13:14