【问题标题】:Functions with other functions as input using delegates in C#使用 C# 中的委托将其他函数作为输入的函数
【发布时间】:2013-03-28 14:59:50
【问题描述】:

我有一些委托和一个方法:

delegate Point Translate(Point p);
delegate Translate Transform(Translate t);

Translate forward = p => new Point(p.X + 1, p.Y);

问题:如何实现这样的方法:

Transform Rotate90 = ??

这样Rotate90 将任何Translate 函数顺时针旋转90。所以:

Point startPoint = new Point(1, 1);
Point endPoint = (Rotate90(forward))(startPoint);
//desired output: Point(1, 0)

编辑 1: 我不会一点一点地应用Translate 函数。我需要的是在一个点上应用一些转换后的函数(Translate 已经旋转或反射的函数)。

我需要什么:我如何写一个Rotate90,如果我将它传递给(p=>new Point(p.X+1, p.y)),它会返回一个与(p=>new Point(p.X, p.Y-1)) 效果相同的函数。

编辑 2: 一些示例:

Translate forward =         p => new Point(p.X + 1, p.Y);
Translate backward =        p => new Point(p.X - 1, p.Y);
Translate downward =        p => new Point(p.X, p.Y - 1);
Translate runningForward =  p => new Point(p.X + 5, p.Y);

Transform Rotate90Cw = ??

Point samplePoint = new Point(1, 1);

Point p1 = (Rotate90Cw(forward))(samplePoint);          //must be (1,0)
Point p2 = (Rotate90Cw(backward))(samplePoint);         //must be (1,2)
Point p3 = (Rotate90Cw(downward))(samplePoint);         //must be (0,1)
Point p4 = (Rotate90Cw(runningForward))(samplePoint);   //must be (1,-4)
Point p4 = (Rotate90Cw(Rotate90Cw(forward)))(samplePoint);   //must be (0,1)

我需要一个单个 Rotate90Cw 函数,它可以应用于任何Translate 函数并返回正确的Translate 函数。所以在一个点上应用Rotate90Cw(forward) 的效果与在一个点上应用downward 的效果是一样的。等等……

我不会为每种情况创建单独的 Rotate 函数(例如 forwardRotated、downRotated 和 ...

【问题讨论】:

  • 如何使用与 LINQ 设计相同的扩展方法覆盖?

标签: c# delegates lambda anonymous-function


【解决方案1】:

不清楚您是否真的需要两个代表。看来您真的希望 one 代表从Point 到Point 的任意转换 - 然后您可以组合转换。例如:

delegate Point Transform(Point input);

private static Transform Compose(Transform first, Transform second)
{
    return p => second(first(p));
}

Transform forward = p => new Point(p.X + 1, p.Y);
Transform rotate90 = p => new Point(p.Y, -p.X);
Transform forwardThenRotate = Compose(forward, rotate);

编辑:看起来你真正想要的是一个转换(进行转换),如下所示:

  • 将原始变换应用于 (0, 0)
  • 旋转结果
  • 将传入点翻译那么多

我们可以轻松做到:

Transform forward = p => new Point(p.X + 1, p.Y);
Transform rotate90 = p => new Point(-p.Y, p.X);
Point forwardRotatedPoint = rotate90(forward(new Point(0, 0));

Transform forwardRotated = p => new Point(forwardRotatedPoint.X + p.X,
                                          forwardRotatedPoint.Y + p.Y);

正如我在别处所说,您可能实际上想要一个Vector 类型,它具有X 和Y 组件...那么您可以有几个可组合的概念:

  • 从向量创建转换(点到点)
  • 旋转一个向量以创建另一个向量
  • 组合转换

【讨论】:

  • 定义接受一个点并返回另一个点的Rotate 没有意义。 Rotate 期望得到一个向量,这里的 Translate 委托是与向量最相似的东西。
  • @HosseinNarimaniRad:我完全不同意 - 这是围绕原点的旋转。我认为它作为点上的函数和任意变换上的函数更有意义。 (如果你的意思是你的Translate 是只是一个固定的翻译,那应该使用类似矢量的类型,而不是委托。)
  • 在这种情况下你是正确的。但我不会在一点上应用一些地图功能。我想在一个点上应用一些转换后的地图函数。
  • @HosseinNarimaniRad:恐怕您还没有明确提出您的要求。不过,我已经提供了一个示例来说明如何进行转换 - 我希望这已经足够了。如果不是,你真的需要澄清你的问题。
  • 我编辑了我的帖子。顺便说一句,您的Compose 的输出是Point 而不是Transform(如您所写)。
【解决方案2】:

我是这样解决的(已编辑):

Translate Rotate90Cw(Translate moveFunction)
{
    return Rotate(moveFunction, Math.PI / 2.0);
}

Translate Rotate(Translate moveFunction, double angle)
{
    Point tempPoint = moveFunction(new Point(0, 0));
    double sin = Math.Sin(angle);
    double cos = Math.Cos(angle);
    return p => new Point(p.X + tempPoint.X * cos + tempPoint.Y * sin,
                           p.Y - tempPoint.X * sin + tempPoint.Y * cos);
}

检查它是否工作:

Rotate90Cw(Rotate90Cw(runningForward))(new Point(1, 1)); //output: (-4,0.9999999)
Rotate90Cw(runningForward)(new Point(1, 1));             //output: (1,-4)
Rotate90Cw(backward)(new Point(1, 1));                   //output: (1,2)
Rotate90Cw(downward)(new Point(1, 1));                   //output: (0,1)

【讨论】:

  • 对,这与我使用的方法基本相同,只是接受一个角度(尽管名称中仍然奇怪的是 90)——但我仍然认为 Translate 应该有不同的类型。平移不是任意的点对点转换:它是向量的添加。所以最好将其表示为一个向量开始。
猜你喜欢
  • 1970-01-01
  • 2022-08-24
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 2012-01-30
  • 2022-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多