C# 中是否有办法在预计算的回调函数中传递所有聚合

本文关键字:函数 回调 计算 是否 | 更新日期: 2023-09-27 18:34:57

我有这样一个方法:

internal PointGeospatial ConvertToSpherical(double x, double y, double z)

我想知道,是否存在这样的可能性,可以在 C# 中以某种函数式风格处理方法中的所有参数,例如(伪代码(:

ConvertToSpherical(double x, double y, double z) ::(x) -> arg->Rad2Deg(x)

这是一个伪代码,但通过这个想法,我认为你得到了我想要的。当然有制作子方法的方法,例如PrepareCoordinates(x, y, z) foreach中我将准备 3 个变量并发送到 ConvertToSpherical() ,但这太势在必行了。

我想要一些很酷的lamda喜欢(功能语言(风格。我的问题可以在 C# 中吗?

C# 中是否有办法在预计算的回调函数中传递所有聚合

我对你的问题的理解是,你想使用 Rad2Deg 方法将每个参数投影到一个新值上,该方法的签名和返回类型就像一个Func<double, double>

我没有看到任何特别好的方法。最好的也许是:

internal PointGeospatial ConvertToSpherical(double x, double y, double z)
{
  var changedArgs = new[] { x, y, z, }.Select(Rad2Deg).ToArray();
  // rest of method
}

但它不会更改原始变量,因此您仍然可以意外地使用 xyz

如果您将方法的签名更改为采用数组(使用 params ,因此您仍然可以使用相同的调用语法调用它(,您可以执行以下操作:

internal PointGeospatial ConvertToSpherical(params double[] x)
{
  for (int i = 0; i < x.Length; ++i)
    x[i] = Rad2Deg(x[i]);
  // rest of method
}

我也可以用箭头做最后一种情况,但它有点丑。你需要这个:

namespace N
{
  delegate void ActionWithRef<T>(ref T obj);
  static class MyExtensions
  {
    public static void ForEachWithRef<T>(this T[] array, ActionWithRef<T> action)
    {
      for (int i = 0; i < array.Length; ++i)
        action(ref array[i]);
    }
  }
}

然后你可以做:

// ugly?
// included in this post because it looks a bit like the pseudocode of your question
internal PointGeospatial ConvertToSpherical(params double[] x)
{
  x.ForEachWithRef((ref double t) => t = Rad2Deg(t));
  // rest of method
}

也许不那么丑陋:

namespace N
{
  static class MyExtensions
  {
    public static void MutateAll<T>(this T[] array, Func<T, T> selector)
    {
      for (int i = 0; i < array.Length; ++i)
        array[i] = selector(array[i]);
    }
  }
}

并与:

internal PointGeospatial ConvertToSpherical(params double[] x)
{
  x.MutateAll(Rad2Deg);
  // rest of method
}

当你只有三个参数时,我不会说我实际上推荐这些"解决方案"中的任何一个,但它显示了你在 C# 中可以做什么(和不能做什么(。

在我使用 params 的所有情况下,如果 ConvertToSpherical 的调用者选择以未展开的形式调用该方法,并且如果他保留对他传递的double[]实例的引用,那么他会发现当方法返回时,他的数组的内容已更改。

同样对于params示例,当然不会在编译时检查传递了多少参数(正好是三个(。

下面是重复的非功能性解决方案:

internal PointGeospatial ConvertToSpherical(double x, double y, double z)
{
  x = Rad2Deg(x);
  y = Rad2Deg(y);
  z = Rad2Deg(z);
  // rest of method
}

;-(

抱歉匆

忙阅读 Q。这里有一个想法,使用 IEnumerables 作为向量:

Func<IEnumerable<double>, IEnumerable<double>> convertToSpherical = a => a.Select(Rad2Deg);
var list = new[] {0, Math.PI, Math.PI*2};
var newList = convertToSpherical(list);
foreach (var i in newList)
{
    Console.WriteLine(i);
}

哪里:

private static double Rad2Deg(double radians)
{
    return radians*180/Math.PI;
}

我发现拥有 xyz变量是一种痛苦,无论如何都容易出现复制粘贴错误,因此总是建议使用 array s/IEnumerable 向量。