如果我在错误的社区发帖,我很抱歉,我在这里很新。
我有多个方法使用相同的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
}
}
如何创建一种方法来实现我的目标(我不想重复代码)尊重上述规则?
答案 0 :(得分:8)
您总是可以将委托传递给该方法,然后您可以基本上做任何您想做的事情。
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);
});
答案 1 :(得分:1)
代表们在很多情况下非常方便,在这种情况下肯定是这样。我知道这已经得到了回答并且是正确的,但这里有一个比较的替代方案。我提供了一个链接,为您提供一些见解。
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);
旁注: 如果在代表列表中找不到计算方法,我会建议一些异常处理。示例如下:(用以下内容替换calculate方法。)
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);
}
}
}
体面教程: Delegates and Events
答案 2 :(得分:0)
您可以使用代理人。 (谷歌它 - 我面前没有开发环境为你准备样品)。基本上是一个让委托调用的方法: 这是伪代码......
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
}
}
}
我用Google搜索“c#delegate as parameter”并提出了http://msdn.microsoft.com/en-us/library/ms173172.aspx,这似乎是一个合理的解释。
答案 3 :(得分:0)
正如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
请注意,您不能在作为委托传递的方法之后放置参数括号!
答案 4 :(得分:-1)
您可以像其他答案提供的那样使用代理,但我相信您这样做会导致代码过于混乱。如果在每种方法中重新声明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;
}