根据作为方法参数传递的运算符执行计算 [已关闭]

perform calculation based on the operator passed as method parameter [closed]

提问人:StackUseR 提问时间:11/1/2023 最后编辑:TylerHStackUseR 更新时间:11/1/2023 访问量:62

问:


想改进这个问题吗?更新问题,使其仅通过编辑这篇文章来关注一个问题。

18天前关闭。

我正在尝试根据作为方法参数传递的运算符进行算术运算。我可以通过多种方式执行此操作,但问题是我有一个要操作的数据表。我无法传递特定的数据行,因为我有许多数据行要操作。

我做了什么:我知道这可以以委托方式完成。类似于答案 - 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
}

我想以一种非常通用的方式(代码可重用性)实现这一点,而不是为不同的运算符进行方法重载或切换,并一遍又一遍地编写相同的代码行。

C# 泛型 运算符 代码重用

评论

0赞 jdweng 11/1/2023
数据表行需要像数组 dt[“name”] 或 dt[index] 一样被索引
0赞 StackUseR 11/1/2023
@jdweng:就像这样 dt[“name”]。
2赞 Palle Due 11/1/2023
你是个怪物。它看起来像一个函数,但它从 UI 中获取一个值,更改 UI 上的一个值,对 result、beforeoperation、a1 和 a2 有副作用,并且有一个未命名的任意常量。方法和函数应该做一件事,并且把它们做好,函数不应该有副作用。MainOperationSimplifeid
0赞 Palle Due 11/1/2023
此外,我不明白这个问题。
1赞 JonasH 11/1/2023
通用数学,但我不确定它是否有帮助。您可能应该看看是否有其他方法可以实现您的任何目标。我可能会尝试尽早将 DataTable 行转换为实际的类型化对象,并在这些对象上使用方法以获得尽可能多的功能。

答:

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);DivisionMultiply
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 创建一个新项目时,前两种方法都有效。但最后一种方法适用于我正在从事的项目。非常感谢!!