【问题标题】:how to avoid this duplicate code by using delegates / lambdas如何通过使用委托/lambdas 来避免这种重复的代码
【发布时间】:2011-01-01 02:29:52
【问题描述】:

我在下面有这段代码,它通过数据结构循环构建字典。

我将这段代码重复了多次,唯一的区别是字典的键

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

  task.Project + task.Name

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

 task.Project

或者只是

 task.Name

这是一个硬编码“桶”方法的示例。

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

最好的方法是什么??

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;
}

【问题讨论】:

    标签: c# lambda delegates code-duplication


    【解决方案1】:

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

    选项 1 — 代表

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

    非常适合在高度本地化的场景中使用(即实现和使用私有的单个类),只需几个简单的密钥构建表达式。

    选项 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) { … }
    }
    

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

    选项 3 — 分解成一个接口

    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;
            …
        }
    }
    

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

    【讨论】:

    • 选项#1调用该函数的代码是什么样的?另外,我认为您的选项#1 答案中有错字
    • @ooo … = BucketByProjectTask(…, task =&gt; task.Project + task.Name) 例如。
    • 谢谢。 .原来我几乎是这样做的,但我有另一个微妙的错误让我失望。 .
    • 用另一个选项(基于界面的设计)和基本使用建议编辑了我的答案。
    猜你喜欢
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多