避免多个类似的 C#

本文关键字: | 更新日期: 2023-09-27 18:33:56

如果我发帖到错误的社区,我深表歉意,我在这里很新。

我有多个方法使用相同的 foreach 循环,只更改我调用的内部方法:

    public void CalculationMethod1()
    {
        foreach (Order order in ordersList)
        {
            foreach (Detail obj_detail in order.Details)
            {
                CalculateDiscount(obj_detail);
            }
        }
    }
    public void CalculationMethod2()
    {
        foreach (Order order in ordersList)
        {
            foreach (Detail obj_detail in order.Details)
            {
                CalculateTax(obj_detail);
            }
        }
    }

每个内部方法都有不同的逻辑、数据库搜索、数学计算(这里不重要(。

我想调用上面的方法,而不是每次都重复foreach循环,所以我通读了下面的解决方案:

    public void CalculateMethod_3()
    {
        foreach (Order obj_order in ordersList)
        {
            foreach (Detail obj_detail in order.Details)
            {
                CalculateDiscount(obj_detail);
                CalculateTax(obj_detail);
            }
        }
    }

但是我陷入了一个规则问题:

 class Program
 {
    static void Main(string[] args)
    {
        Calculation c = new Calculation();
        c.CalculateMethod_3();
        c.AnotherMethod_4(); //It doesn't use objDetail
        c.AnotherMethod_5(); //It doesn't use objDetail
        c.CalculateMethod_6(); //Method 6 needs objDetail but respecting the order of the methods, so It must be after AnotherMethod_4 and AnotherMethod_5
    }
 }

如何创建一种方法来实现我的目标(我不想重复代码(遵守上述规则?

避免多个类似的 C#

您始终可以将委托传递给该方法,然后基本上可以执行任何您想要的操作。

public void ApplyToDetails(Action<Detail> callback)
{
    foreach (Order order in ordersList)
    {
        foreach (Detail obj_detail in order.Details)
        {
            callback(obj_detail);
        }
    }       
}

然后使用你会做这样的事情

ApplyToDetails(detail => CalculateTax(detail));
ApplyToDetails(detail =>
{
    CalculateDiscount(detail);
    CalculateTax(detail);
});

在许多情况下,代表非常方便,在这种情况下绝对如此。我知道这已经得到了回答,而且是正确的,但这里有一个比较的替代方案。 我提供了一个链接来为您提供一些见解。

public class CalculationMethods
{
    public delegate void CalculationDelegate(Detail method);
    private Dictionary<string, CalculationDelegate> _methods;
    public CalculationMethods
    {
        this._methods = new Dictionary<string, CalculationDelegate>()
        {
            { "Discount", CalculateDiscount },
            { "Tax",      CalculateTax      }
        };
    }
    public void Calculate(string method, Detail obj_detail)
    {
        foreach (Order order in ordersList)
        {
            foreach (Detail obj_detail in order.Details)
            {
                var m = this._methods.FirstOrDefault(item => item.Key == method).Value;
                m(obj_detail);
            }
        }
    }
}

用法:

//Initialize
var methods = new CalculationMethods();
//Calculate Discount
methods.Calculate("Discount", obj_detail);
//Calculate Tax
methods.Calculate("Tax", obj_detail);

旁注:我建议进行一些异常处理,以防在委托列表中找不到计算方法。下面的示例:(将计算方法替换为以下内容。

public void Calculate(string method, Detail obj_detail)
{
    foreach (Order order in ordersList)
    {
        foreach (Detail obj_detail in order.Details)
        {
            var m = this._methods.FirstOrDefault(item => item.Key == method).Value;
            //Check if the method was found
            if (m == null)
                throw new ApplicationNullException("CalculationDelegate")
            m(obj_detail);
        }
    }
}

体面的教程:参会代表和活动

您可以使用委托。(谷歌它 - 我面前没有开发环境来为你运行一个示例(。基本上是一个需要委托调用的方法:这是伪代码...

public void CalculationMethod(delegate myFunction) // need to look up correct param syntax
{
    foreach (Order order in ordersList)
    {
        foreach (Detail obj_detail in order.Details)
        {
            myFunction(); // Need to lookup correct calling syntax
        }
    }
}

我在谷歌上搜索了"c# 委托作为参数"并提出了 http://msdn.microsoft.com/en-us/library/ms173172.aspx 这似乎是一个合理的解释。

正如Darren Kopp所说,你可以使用委托。但是,如果您要使用参数调用方法,则可以直接调用它(不需要 lambda 表达式(。

public void ApplyToDetails(Action<Detail> callback) { ... }

ApplyToDetails(Method_1);         // Uses objDetail
ApplyToDetails(d => Method_2());  // Doesn't use objDetail
ApplyToDetails(d => Method_3());  // Doesn't use objDetail
ApplyToDetails(Method_4);         // Uses objDetail

请注意,不得在作为委托传递的方法之后放置参数大括号!

您可以使用委托,因为其他答案提供了,但我相信在您的情况下这样做会导致代码过于混乱。如果在每个方法中重新声明 foreach 循环,则代码会更清晰、更具可读性。只有当你复制粘贴内部的部分时,我才会说你冒着代码重复的风险。

可以这样想:如果你创建了一个传入委托的方法,那么这个方法的名字会叫什么?这是一种方法,可以为您传入的每个订单中的每个细节执行某些操作,并且应该命名为类似 DoSomethingForEachDetailInOrders() .此方法将用于哪种类?你不知道你在委托中实际在做什么,所以这个类的目的必须是更多的框架风格的代码,你的应用似乎不够复杂,无法保证。

此外,如果您正在调试此代码或通读它,而不是能够在您正在读取的方法中看到 2 个 foreach 循环,您必须滚动到委托的定义,阅读该定义,然后返回到您的方法并继续读取。

编辑:我最初通过淡化foreach循环的重复来回答这个问题,希望OP不会给他的应用程序增加额外的复杂性,试图使其遵循"最佳实践"。我没有深入,因为代码需要更具侵入性的重构才能实现可维护性。foreach 循环代码气味源于其他问题,详见本答案下方的注释。我仍然坚持我的观点,即添加委托方法不如重复循环可取,因为委托方法选项几乎是教科书式的样板。

添加了一个代码示例来解释如果可维护性是一个问题,应如何重构代码:

public decimal CalculateDiscount(IEnumerable<Order> ordersList)
{
    return ordersList.SelectMany(order => order.Details).Sum(detail => detail.Discount);
}
public decimal CalculateTax(IEnumerable<Order> ordersList)
{
    return ordersList.SelectMany(order => order.Details).Sum(detail => detail.Total) * taxRate;
}

如果您绝对必须有一个自定义函数来获取订单的所有详细信息(可以重构为扩展方法(:

public IEnumerable<Detail> GetDetailsForOrders(IEnumerable<Orders> orderList)
{
    foreach(var order in orderList)
    {
        foreach (var detail in order.Details)
        {
            yield return detail;
        }
    }
}
public decimal CalculateDiscount(IEnumerable<Order> ordersList)
{
    return GetDetailsForOrders(ordersList).Sum(detail => detail.Discount);
}
public decimal CalculateTax(IEnumerable<Order> ordersList)
{
    return GetDetailsForOrders(ordersList).Sum(detail => detail.Total) * taxRate;
}
相关文章:
  • 没有找到相关文章