在 Func<> 调用中检查除以零的情况

4

我将尝试使用动态数学运算符处理二维数组。

以下是相关的方法:

public float[,] Calculate(int[,] a, int[,] b, Func<int,int,float> compute)
{
   int columns = a.GetLength(0);
   int rows = a.GetLength(1);
   float[,] result = new float[columns,rows];

   for(int i = 0; i < columns; i++)
   {
       for(int j = 0; j < rows; j++)
       {
            result[i,j] = compute(a[i,j], b[i,j]);      
       }
   }
   return result;
}

这个方法的调用方式如下:

int[,] a = new int[2,3] { {2, 6, 19}, {3, -4, 25}};
int[,] b = new int[2,3] { {12, -2, 11}, {1, -11, 0}};

//1
float[,] c = Calculate(a, b, (x,y) => (x+y));
//2
float[,] c = Calculate(a, b, (x,y) => (x-y));
//3
float[,] c = Calculate(a, b, (x,y) => (x*y));
//4
float[,] c = Calculate(a, b, (x,y) => (x/y));

现在,虽然版本1到3运行得非常顺畅,但是版本4迟早会抛出异常。 处理这种情况的一种方法是使用try catch块:

try 
{
    result[i,j] = compute(a[i,j], b[i,j]);      
}
catch(DivideByZeroException ex)
{
    result[i,j] = 0;
}

看起来我在使用try-catch进行流程控制,而我宁愿避免这种做法(此外,结果是错误的)。有没有一种方法可以检查函数调用中的除法运算符是否为/,并检查第二个数组是否包含0,如果是,则返回null?


2
请注意,这将导致整数除法,因此5/2等于2而不是2.5。您需要将至少一个参数转换为浮点数以获得实数(float)。 - Nikola Davidovic
1
只需让 Calculate 抛出异常并在调用者(或调用者的调用者)中处理它。 - Henrik
“仅返回null”是指您打算更改函数签名以返回float?[,]吗?如果是这样,我们可以将“compute”的定义更改为<int,int,float?>。 如果是这样,我们是否可以允许“compute”决定其参数是否有意义,并决定何时返回“null”? - Damien_The_Unbeliever
@Damien_The_Unbeliever 可以的 - 你可以。 - Marco
2个回答

2
常规的流程控制怎么样?使用if语句?
float[,] c;

if (b != 0)
    c = Calculate(a, b, (x,y) => (x/y));
else
    c = 0;

1

这可能看起来像一个有点奇怪的解决方案,但你可以用随机数测试你的函数并检查结果,如果结果总是1,那么它就是一个除法运算:

static bool IsDivision(Func<int, int, float> func)
{
    var rnd = new Random();

     return  Enumerable.Range(0, 10)
            .Select(x => rnd.Next(100))
            .All(x => Math.Abs(func(x, x) - 1) < 0.000001);
}

在执行操作之前,您可以将您的函数传递给此方法并执行相应的操作:

if(IsDivision(compute) &&  b.OfType<int>().Any(x => x == 0)) return null;

但我同意这不是一个好的解决方案,例如这将无法处理(x,y) => 1,但我假设你知道自己在做什么,并且不会将那种奇怪的表达式传递给你的函数 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接