【问题标题】:How to pass an expression to a method when the variables in the expression are inside the scope of the method当表达式中的变量在方法范围内时如何将表达式传递给方法
【发布时间】:2012-07-04 23:55:50
【问题描述】:

我一定错过了 lambda 和委托的一些基础知识。就这样吧。。

我有两个功能“几乎”相同的事情。我需要通过将它们写入一个函数并传递“必要”参数来对它们进行 OOP。

这两个函数大致是这样的:

private static bool Populate1(int yPoint)
{
    //---------------------------------
    //--------------------------------
    int xPoint = 0;

    foreach (var item in collection)
    {
        ComboBox cb = AddControl_Combo(item, xPoint, yPoint);

        xPoint += cb.Width + 12;
        yPoint = 0;
    }

    //-------------------------------
    //-------------------------------

    return true;
}

private static bool Populate2(int yPoint)
{
    //---------------------------------
    //--------------------------------
    int xPoint = 0;

    foreach (var item in collection)
    {
        ComboBox cb = AddControl_Combo(item, xPoint, yPoint);

        yPoint += cb.Height + 12;
    }

    //---------------------------------
    //--------------------------------

    return true;
}

这些函数要冗长得多,所以我真的想把它们干掉。可以注意到,这两个函数的唯一区别是两个定位函数

xPoint += cb.Width + 12;
yPoint = 0;

yPoint += cb.Height + 12;

如何通过将上述表达式作为参数将上述两个函数合二为一?我发现的问题是变量xPointcb 是函数范围内的变量!

这是我尝试并成功的方法,但在我看来并不优雅:

private static bool Populate(ref int xPoint, ref int yPoint, ref ComboBox cb, 
                              Action positioningFunc)
{
    foreach (var item in collection)
    {
        cb = AddControl_Combo(item, xPoint, yPoint);

        positioningFunc();
    }

    return true;
}

并称它为:

int xPoint = 0;
int yPoint = 0;
ComboBox cb = null;
return Populate(ref xPoint, ref yPoint, ref cb, () =>
{
    xPoint += cb.Width + 12;
    yPoint = 0;
});

int xPoint = 0;
int yPoint = 19;
ComboBox cb = null;
return Populate(ref xPoint, ref yPoint, ref cb, () =>
{
    yPoint += cb.Height + 12;
});

有没有更好的 OOP 方法?

编辑: 我试图传递一些动态控件的两个表达式(水平、垂直、对角线、之字形等)。该函数已经从 4 个不同的地方调用并且可以扩展。为了获得表达式本身,我们从调用类中进行了大量计算。因此,在Populate 函数(位于单独的实用程序类中)中执行if else 逻辑并不是我想要的。所有方法中唯一的变化是foreach中的那些定位表达式。所以我正在寻找在这种情况下如何传递参数。

【问题讨论】:

  • 在 lambda 中使用参数。
  • 使用 lamdas 会增加一些开销(函数调用和减少本地优化的机会)。对于大多数代码来说,这无关紧要,但如果你有很多点可能会对用户感知产生影响。
  • @SLaks 我不太擅长 lambda .. 你能发布一个示例代码吗?我不确定如何在 lambda 中使用参数,然后从方法中使用它
  • nawfal,您可以对两个命名参数 xpoint 和 ypoint 进行签名。在方法内部,您根据收到的参数应用位置。不需要 Lambda。
  • 算了,毕竟我们只是在谈论 yPoint

标签: c# c#-4.0 lambda dry argument-passing


【解决方案1】:

如果您需要通过 Lambdas 完成,这里有一个替代方案:

 private static bool Populate(int yPoint, Func<ComboBox, Point, Point> modifier)
 {
    var point = new Point (0, yPoint);
    foreach (var item in collection)
    {
        ComboBox cb = AddControl_Combo(item, point.X, point.Y);
        point = modifier(cb, point);
    }
    return true;
}

这两个电话将是:

Populate(0, (cb, point) => new Point(point.X + cb.Width + 12, 0));
Populate(0, (cb, point) => new Point(0, point.Y + cb.Height + 12));

您也可以使用Tuple&lt;int, int&gt;,但Point 更简洁。

【讨论】:

  • 非常感谢。正是我需要的。
【解决方案2】:

简单的逻辑

private static bool Populate(int yPoint, bool flag)
{
    int xPoint = 0;

    foreach (var item in collection)
    {
        var ComboBox cb = AddControl_Combo(item, xPoint, yPoint);

        if(flag)
        {
            xPoint += cb.Width + 12;
            yPoint = 0;
        }
        else
        {
            yPoint += cb.Height + 12;
        }
    }

    return true;
}

当您需要 Populate1 时,请致电 Populate(valueofypoint, true)Populate(valueofypoint, false) 进行 Populate2 呼叫。

【讨论】:

    【解决方案3】:

    这应该完全按照您的需要工作:

    private static bool Populate(int yPoint,
        Func<int, ComboBox, int> xStep,
        Func<int, ComboBox, int> yStep)
    {
        int xPoint = 0;
    
        foreach (var item in collection)
        {
            ComboBox cb = AddControl_Combo(item, xPoint, yPoint);
    
            xPoint = xStep(xPoint, cb);
            yPoint = yStep(xPoint, cb);
        }
    
        return true;
    }
    

    你就这样称呼它:

    Populate(42, (x, cb) => x + cb.Width + 12, (y, cb) => 0);
    Populate(42, (x, cb) => 0, (y, cb) => y + cb.Width + 12);
    

    这是你所期待的吗?

    【讨论】:

    • 更简单。像这样。但我发现@Pablo Romeo 的答案更容易调用。
    【解决方案4】:

    结合您的想法和 Nikhil 的建议:

    private static bool Populate(int yPoint, int position)
    {
        int xPoint = 0;
    
        ComboBox cb;
    
        Action positionFunction;
        if (position == 1)
        {
                positionFunction = () => { 
                        xPoint += cb.Width + 12;
                        yPoint = 0;
                };
        }
        else if (position ==2)
        {
                positionFunction = () => { yPoint += cb.Height + 12; };
        }
        else
        {
                throw new Exception("Invalid position");
        }
    
        foreach (var item in collection)
        {
            cb = AddControl_Combo(item, xPoint, yPoint);
    
            positionFunction();
        }
    
        return true;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-30
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      • 2013-04-19
      相关资源
      最近更新 更多