提问人:StackUseR 提问时间:11/1/2023 最后编辑:TylerHStackUseR 更新时间:11/1/2023 访问量:62
根据作为方法参数传递的运算符执行计算 [已关闭]
perform calculation based on the operator passed as method parameter [closed]
问:
我正在尝试根据作为方法参数传递的运算符进行算术运算。我可以通过多种方式执行此操作,但问题是我有一个要操作的数据表。我无法传递特定的数据行,因为我有许多数据行要操作。
我做了什么:我知道这可以以委托方式完成。类似于答案 - https://stackoverflow.com/a/44333156
public int MainOperationSimplifeid(Func<int, int, int> operatoru)
{
if (beforeoperation == 2)
{
a2 = Convert.ToInt32(textBox1.Text);
textBox1.Text = "";
result = operatoru(a1, a2);
// textBox1.Text = Convert.ToString(result);
a1 = 0;
a2 = 0;
}
beforeoperation++;
return result;
}
我知道,我也可以通过使用枚举或开关,甚至通过方法重载来实现这一点。但是我的代码已经庞大而复杂,具有多种支持方法。所以我不想增加更多的复杂性。
我需要什么:我可以做这样的事情吗?
void MethodName(DataTable dt, int operand, char op)
{
//few lines of code
dt.SomeRowName1 = (double)dtRowValue op operand;
//few lines of code
dt.SomeRowName2 = (double)dtRowValue op operand;
dt.SomeRowName3 = (double)dtRowValue op operand;
//few lines of code
}
我想以一种非常通用的方式(代码可重用性)实现这一点,而不是为不同的运算符进行方法重载或切换,并一遍又一遍地编写相同的代码行。
答:
0赞
shingo
11/1/2023
#1
您可以搜索带有反射的运算符方法,然后从中创建委托。
static Func<T, T, T> FindOperator<T>(string op)
{
var m = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
.First(mi => mi.Name.EndsWith($"op_{op}"));
return (Func<T, T, T>)Delegate.CreateDelegate(typeof(Func<T, T, T>), m);
}
// Usage
FindOperator<int>("Division")(7, 2);
FindOperator<double>("Addition")(7.1, 2.3);
此方法应适用于 .Net 6 以来的数值类型。
如果您担心效率,可以缓存结果。
如果你想知道“op”可以取哪些值,请查看文档中相应类型-->https://learn.microsoft.com/en-us/dotnet/api/system.int32 的长长的“Implements”列表。
通过在运算符中指定每个参数的类型,它可以更通用。
static Func<TSelf, TOther, TResult> FindOperator<TSelf, TOther, TResult>(string op)
{
var m = typeof(TSelf).GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
.First(mi => mi.Name.EndsWith($"op_{op}"));
return (Func<TSelf, TOther, TResult>)Delegate.CreateDelegate(typeof(Func<TSelf, TOther, TResult>), m);
}
下面是使用表达式和反射创建运算符方法的另一个示例,这也可以在 .Net Framework 中使用。
static Func<T, T, T> CreateOperator<T>(string op)
{
var l = Expression.Parameter(typeof(T));
var r = Expression.Parameter(typeof(T));
var m = typeof(Expression).GetMethod(op, BindingFlags.Static | BindingFlags.Public, null,
new Type[] { typeof(Expression), typeof(Expression) }, null);
var b = (Expression)m.Invoke(null, new object[] { l, r });
return (Func<T, T, T>)Expression.Lambda(b, l, r).Compile();
}
//Usage
CreateOperator<int>("Multiply")(7, 4);
CreateOperator<float>("Divide")(3.6f, 1.25f);
支持的运算值可在此处找到: https://learn.microsoft.com/en-us/dotnet/api/system.linq.expressions.binaryexpression#binary-arithmetic-operations
评论
0赞
StackUseR
11/1/2023
嗨,Shingo。在这一行中,我试图通过 和 ,但代码中断了。因为 mi.Name 并没有以这个词结束。你能指导一下吗?FindOperator<int>("Division")(7, 2);
Division
Multiply
0赞
shingo
11/1/2023
它需要 .net 6,您使用的是 .net 框架吗?
0赞
StackUseR
11/1/2023
是的!我正在使用 .Net 框架 6
0赞
shingo
11/1/2023
没有 .net framework 6,最新版本是 4.8.1。我添加了一个可以在 .net framework >= 3.5 中使用的新方法。
0赞
StackUseR
11/1/2023
是的,同意!它是 .Net 6。我使用的是 .Net 4.7。但是您给出的两种方法都运行良好。当我使用 .Net 6 创建一个新项目时,前两种方法都有效。但最后一种方法适用于我正在从事的项目。非常感谢!!
评论
MainOperationSimplifeid