当表达式中的变量位于方法范围内时,如何将表达式传递给方法

时间:2012-07-04 23:55:50

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

我一定错过了一些基本的lambdas和代表。这就是..

我有两个功能可以做“几乎”相同的事情。我需要通过将它们写入一个函数并传递“必要的”参数来对它们进行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;
});

是否有更好的方法来支持他们?

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

4 个答案:

答案 0 :(得分:2)

如果你需要通过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<int, int>,但Point更简洁。

答案 1 :(得分:1)

简单逻辑

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通话。

答案 2 :(得分:1)

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

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);

这是你期待的吗?

答案 3 :(得分:0)

结合你的想法和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;
}