我经常需要在代码中执行一些数学运算。 E.g。
var par1 = 100;
var par2 = 200;
var par3 = 300;
var result = (par1 + par2) / par3;
我还想保存用于记录目的的计算步骤。
var loggingMessage = string.Format(
"result = (par1 + par2) / par3; [{0} = ({1} + {2}) / {3}]",
result,
par1,
par2,
par3
);
正如我经常这样做,让我疯狂地做这个猴子的工作。这也很难维持。
我知道可以用例如反向抛光记法来完成,但我不想为这些简单的数学动作产生如此大的过度杀伤力。
是否有针对此问题的智能解决方案?
答案 0 :(得分:4)
嗯,没有太多可以做的来简化这个,但你可以开始使用表达式树:
var par1 = 100;
var par2 = 200;
var par3 = 300;
Expression<Func<int, int, int, int>> expr = (a, b, c) => (a + b) / c;
Func<int, int, int, int> func = expr.Compile();
int result = func(par1, par2, par3);
string exprAsText = expr.ToString();
string exprWithValues = exprAsText.Replace("result", result.ToString())
.Replace("a", par1.ToString())
.Replace("b", par2.ToString())
.Replace("c", par3.ToString());
string logMessage = $"result = {exprAsText} ({result} = {exprWithValues})";
Console.WriteLine(logMessage);
由于您将ops存储为表达式树,因此您可以轻松地使用某些抽象/泛化来打印这些日志消息。
也许您发现以下代码是一种矫枉过正,但它能够胜任:
// Define your mathematical operations in a static class, and use them
// across your solution
public static class MathOps
{
public static Expression<Func<int, int, int, int>> SumAndDivide { get; } = (a, b, c) => (a + b) / c;
}
public static class ExpressionExtensions
{
public static object ExecuteAndLog<TExpr>(this TExpr expr, object args)
where TExpr : LambdaExpression
{
Contract.Requires(expr != null);
Contract.Requires(args != null);
IEnumerable<PropertyInfo> argsProperties =
args.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Contract.Assert(expr.Parameters.Count == argsProperties.Count());
Delegate compiledDelegate = expr.Compile();
string exprAsText = expr.Body.ToString();
string replacedExprAsText = (string)exprAsText.Clone();
List<object> delegateArgs = new List<object>();
foreach (PropertyInfo property in argsProperties)
{
delegateArgs.Add(property.GetValue(args));
replacedExprAsText = replacedExprAsText.Replace(property.Name, property.GetValue(args)?.ToString());
}
object result = compiledDelegate.DynamicInvoke(delegateArgs.ToArray());
string logMessage = $"result = {exprAsText} ({result} = {replacedExprAsText})";
// Replace this with your logger
Trace.WriteLine(logMessage);
return result;
}
}
...你可以这样使用它:
class Program
{
static void Main(string[] args)
{
// You give operation arguments as an object. An anonymous
// object can be enough!
int result = (int)MathOps.SumAndDivide.ExecuteAndLog
(
new
{
a = 100,
b = 200,
c = 300
}
);
Console.Read();
}
}
现在轮到你重构了它。也许,在最终解决方案中,我会将数学运算分开并记录到不同的问题,但由于这只是一个答案,我试图尽可能地使用我提出的代码进行压缩;)
答案 1 :(得分:0)
我会创建一个包含您需要的操作的类myMaths
。
public class myMaths
{
private string _LoggedOperations = "";
public myMaths()
{
_LoggedOperations = "";
}
//(A + B) / C
public double BR_A_plus_B_BR_dev_C(double A, double B, double C)
{
double result = (A + B) / C;
if (_LoggedOperations != "") _LoggedOperations += "\n";
_LoggedOperations += string.Format("result = (A + B) / C; [{0} = ({1} + {2}) / {3}]", result, A, B, C);
return result;
}
//(A - B) / C
public double BR_A_minus_B_BR_dev_C(double A, double B, double C)
{
double result = (A - B) / C;
if (_LoggedOperations != "") _LoggedOperations += "\n";
_LoggedOperations += string.Format("result = (A - B) / C; [{0} = ({1} - {2}) / {3}]", result, A, B, C);
return result;
}
//(A - B) * C
public double BR_A_minus_B_BR_times_C(double A, double B, double C)
{
double result = (A - B) * C;
if (_LoggedOperations != "") _LoggedOperations += "\n";
_LoggedOperations += string.Format("result = (A - B) * C; [{0} = ({1} - {2}) * {3}]", result, A, B, C);
return result;
}
//((A + B) * C) / D
public double BR_BR_A_plus_B_BR_times_C_BR_dev_D(double A, double B, double C, double D)
{
double result = ((A + B) * C) / D;
if (_LoggedOperations != "") _LoggedOperations += "\n";
_LoggedOperations += string.Format("result = ((A + B) * C) / D; [{0} = (({1} + {2}) * {3}) / {4}]", result, A, B, C, D);
return result;
}
public string LoggedOperations
{
get { return _LoggedOperations; }
}
}
并像这样使用它:
private void button1_Click(object sender, EventArgs e)
{
myMaths m = new myMaths();
var par1 = 100;
var par2 = 200;
var par3 = 300;
var par4 = 5;
double result1 = m.BR_A_plus_B_BR_dev_C(par1, par2, par3);
double result2 = m.BR_A_minus_B_BR_dev_C(par1, par2, par3);
double result3 = m.BR_A_minus_B_BR_times_C(par1, par2, par3);
double result4 = m.BR_BR_A_plus_B_BR_times_C_BR_dev_D(par1, par2, par3, par4);
MessageBox.Show(m.LoggedOperations);
}