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

C#:如何在嵌套循环中使用委托处理实例方法以消除代码冗余

解决DogWalker类代码冗余的委托重构方案

场景与原始代码

一位遛狗员拥有多位客户,每位客户饲养一只或多只狗,对应场景的C#原始代码如下:

public class Dog
{
    public int NeedForWalk { get; set; }
    public int NeedForFood { get; set; }

    public Dog()
    {
    }

    public void TakeForWalk(int walkTime)
    {
        // 遛狗会相应降低狗狗的遛弯需求
        NeedForWalk -= walkTime;
    }

    public void GiveFood(int amountOfFood)
    {
        // 喂食会相应降低狗狗的进食需求
        NeedForFood -= amountOfFood;
    }
}

public class Customer
{
    public IEnumerable<Dog> Dogs { get; set; }

    public Customer()
    {
    }
}

public class DogWalker
{
    public IEnumerable<Customer> Customers { get; set; }

    public DogWalker()
    {
    }

    public void walkDogs(int walkTime)
    {
        foreach (Customer customer in Customers)
        {
            foreach (Dog dog in customer.Dogs)
            {
                dog.TakeForWalk(walkTime);
            }
        }
    }

    public void feedDogs(int amountOfFood)
    {
        foreach (Customer customer in Customers)
        {
            foreach (Dog dog in customer.Dogs)
            {
                dog.GiveFood(amountOfFood);
            }
        }
    }
}

重构需求与问题

可以看到DogWalker类的walkDogs()和feedDogs()方法逻辑高度重复,均是遍历所有客户的狗狗并执行对应操作。希望通过辅助方法+委托消除代码冗余,但遇到两个问题:

  1. 如何正确实现applyToDogs(),使其支持Func<int>以外的委托签名;
  2. 如何在walkDogs()和feedDogs()方法中调用applyToDogs()。

解决方案

方案1:使用闭包的简洁实现

通过Action<Dog>委托接收对单个狗狗的操作,调用方利用lambda表达式绑定参数,实现类型安全且简洁的重构:

public class DogWalker
{
    public IEnumerable<Customer> Customers { get; set; }

    public DogWalker()
    {
    }

    public void walkDogs(int walkTime)
    {
        applyToDogs(dog => dog.TakeForWalk(walkTime));
    }

    public void feedDogs(int amountOfFood)
    {
        applyToDogs(dog => dog.GiveFood(amountOfFood));
    }

    #region 辅助方法
    private void applyToDogs(Action<Dog> action)
    {
        foreach (Customer customer in Customers)
        {
            foreach (Dog dog in customer.Dogs)
            {
                action(dog);
            }
        }
    }
    #endregion
}

说明:

  • 辅助方法applyToDogs只负责遍历所有狗狗,将每个狗狗实例传递给传入的Action<Dog>委托;
  • 在walkDogs和feedDogs中,通过lambda表达式把狗狗的实例方法(如TakeForWalk)和当前方法的参数(如walkTime)绑定,生成符合Action<Dog>签名的委托;
  • 这种方式无需处理复杂的参数列表,代码简洁且类型安全,避免了装箱拆箱开销。

方案2:泛型参数的直观实现

如果希望明确传递操作参数,可以使用泛型版本的Action<Dog, T>委托,让参数传递更清晰:

public class DogWalker
{
    public IEnumerable<Customer> Customers { get; set; }

    public DogWalker()
    {
    }

    public void walkDogs(int walkTime)
    {
        applyToDogs((dog, time) => dog.TakeForWalk(time), walkTime);
    }

    public void feedDogs(int amountOfFood)
    {
        applyToDogs((dog, food) => dog.GiveFood(food), amountOfFood);
    }

    #region 辅助方法
    private void applyToDogs<T>(Action<Dog, T> action, T parameter)
    {
        foreach (Customer customer in Customers)
        {
            foreach (Dog dog in customer.Dogs)
            {
                action(dog, parameter);
            }
        }
    }
    #endregion
}

说明:

  • 泛型辅助方法applyToDogs<T>接收两个参数:一个带狗狗实例和操作参数的委托,以及对应的操作参数;
  • 调用时直接传递lambda表达式和参数,逻辑更直观,适合需要明确展示参数传递关系的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 11:38:29