c# - 如何通过使用委托(delegate)/lambda 来避免重复代码

标签 c# lambda delegates code-duplication

我在下面有这段代码,它循环遍历一个数据结构来构建一个字典。

我将此代码复制了多次,唯一的区别是字典的键

所以在下面的代码中它恰好是:

  task.Project + task.Name

这是字典的关键,但在其他情况下它只是:

 task.Project

或者只是

 task.Name

这里是硬编码“Bucket”方法之一的示例。

我的目标是拥有一个通用的“Bucket”方法,我可以在其中进行回调或以某种方式传入用于计算 key 的函数。

这样做的最佳方法是什么??

private Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings)
{
    Dictionary<string, TeamHours> dict = new Dictionary<string, TeamHours>();

    foreach (var name in timebookings.Keys)
    {
        TimeBooking tb = timebookings[name];
        Person p = tb.Person;

        foreach (var booking in tb.WeeklyTimeBookings.Keys)
        {
            var item = tb.WeeklyTimeBookings[booking];
            foreach (var task in item.TaskSlices)
            {
                if (dict.ContainsKey(task.Project + task.Name))
                {
                    TeamHours th = dict[task.Project + task.Name];
                    th.Hours = th.Hours + task.Hours;
                }
                else
                {
                    TeamHours th = new TeamHours();
                    th.Hours = task.Hours;
                    th.Project = task.Project;
                    th.Task = task.Name;
                    th.Workstream = tb.Person.OrganisationalUnitName;
                    dict[task.Project + task.Name] = th;
                }
            }

        }

    }
    return dict;
}

最佳答案

好吧,你基本上自己回答了这个问题。要么将委托(delegate)传递给方法,要么继承不同的实现并通过实现抽象方法来专门化。另一种选择是将 key 构建算法分离为一个接口(interface),这可以实现最佳的关注点分离,但对于简单的场景来说,开销可能太大。

选项 1 — 委托(delegate)

private Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings, Func<string, Task> getTaskKey)
{
    …
    dict[getTaskKey(task)] = th;
    …
}

适用于高度本地化的场景(即实现和使用对单个类私有(private)),只需几个简单的键构建表达式。

选项2——抽象类和方法

class abstract BucketAlgorithm
{
    protected abstract string GetTaskKey(Task task);


    public  Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings)
    {
        …
        dict[GetTaskKey(task)] = th;
        …
    }
}

class SpecificBucketAlgorithm : BucketAlgorithm
{
    protected override string GetTaskKey(Task task) { … }
}

适合在中等范围内使用,例如一个程序集,不需要更好地分离关注点(接口(interface)与实现),或者需要多种重要的 key 构建算法。

选项 3 — 分解为一个接口(interface)

interface ITaskKeyGenerator
{
    string GetTaskKey(Task task);
}

class BucketAlgorithm
{
    public BucketAlgorithm(ITaskKeyGenerator taskKeyGenerator)
    {
        this.taskKeyGenerator = taskKeyGenerator;
    }

    private ITaskKeyGenerator taskKeyGenerator;

    public  Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings)
    {
        …
        dict[taskKeyGenerator.GetTaskKey(task)] = th;
        …
    }
}

适用于需要彻底分离关注点或可能存在多个复杂的 key 构建算法,甚至由 API 用户从“外部”提供的场景。

关于c# - 如何通过使用委托(delegate)/lambda 来避免重复代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4571574/

相关文章:

C#:声明所有配置的预处理器符号

c# - 正则表达式匹配空格之间的单词

c# 无法编辑数据集中的数据行

Python 3,为什么只有函数和部分在多处理 apply_async 中起作用,但闭包和 lambda 都不起作用

ios - 如何连接来自 xib 中自定义类的委托(delegate)?

swift - 如何在 Swift 中对委托(delegate)方法的异步调用进行单元测试?

objective-c - 如何将基于委托(delegate)的回调系统转换为基于 block 的?

c# - 循环语句不超过第二项

java - 为什么 Java 编译器不能从约束 Iterable< 中推断出 Iterable<String>?扩展 CharSequence> 和 () -> (Iterator<String>)

java - Kotlin 如何在包含在 Lambda 中时指定返回标签