有没有办法在C#中内联委托?

时间:2013-02-26 00:59:08

标签: c# delegates inline

这是我正在处理的简化方案。循环结构有多种方法。

for (int i=0; i<I; i++) {
    // Do something
    for (int j=0; j<J; j++) {
        // Do something
        for (int k=0; k<K; k++) {
            // Do something
            Update(a,b,c);
        }
    }
}

在一种方法中,更新(a,b,c)是

a[i] += b[j] * c[k]

在另一种方法中,它是

b[j] += a[i] * c[k]

然而在另一种方法中,它是

c[k] += a[i] * b[j]

目前,我的代码到处都是重复的。 C#中是否有一个模式,以便我不重复代码?我很想使用委托,但似乎委托会降低性能(这在我的情况下很重要)。

有没有办法为这种情况编写宏或内联委托函数?

5 个答案:

答案 0 :(得分:11)

这样的东西?

void DoUpdates(Action<int, int, int> update)
{
  for (int i=0; i<I; i++) {
    // Do something
    for (int j=0; j<J; j++) {
      // Do something
      for (int k=0; k<K; k++) {
        // Do something
        update(i, j, k);
      }
    }
  }
}

然后在来电者

DoUpdates((int i, int j, int k) => { a[i] += b[j] * c[k]; });

这就是你要找的东西吗?

答案 1 :(得分:4)

void Update<T>(T[] x, T[] y, T[] z, int i, int j, int k)
{
    x[i] += y[j] * z[k];
}

用法:

Update(a, b, c, i, j, k);
Update(b, a, c, j, i, k);
Update(c, a, b, k, i, j);

我发现a总是被i访问(依此类推 - b jc k)。您可以尝试使用此事实来优化代码。

答案 2 :(得分:2)

如果性能至关重要,你可以避免内循环中的方法调用,如下所示:

void Update(int[]x, int[]y, int[]z, int I, int J, int K)
{
    for (int i = 0; i < I; i++)
    {
        // Do something
        for (int j = 0; j < J; j++)
        {
            // Do something
            for (int k = 0; k < K; k++)
            {
                // Do something
                x[i] += y[j] * z[k];
            }
        }
    }
}

和调用代码:

Update(a, b, c, I, J, K);
Update(b, a, c, J, I, K);
Update(c, a, b, K, I, J);

答案 3 :(得分:0)

可能你正在实现大数乘法或其他向量线性组合之类的东西。你需要你描述为内联委托的方法的原因很可能是因为在计算过程中存储结果的位置不同,而且嵌套的for循环是硬编码的。因此,我建议修改您的代码如下:

public void Update(int destinationIndex, int[][] arrays, int[] indices) {
    var product=1;

    for(var i=indices.Length; i-->0; )
        if(destinationIndex!=i)
            product*=arrays[i][indices[i]];

    arrays[destinationIndex][indices[destinationIndex]]+=product;
}

public void PerformUpdate(
    int destinationIndex, int[] counts, int[][] arrays, Action<int, int>[] actions,
    List<int> indices=null, int level=0
    ) {
    if(level==counts.Length)
        Update(destinationIndex, arrays, (indices??new List<int>()).ToArray());
    else
        for(int count=counts[level], i=0; i<count; i++) {
            if(null!=actions&&level<actions.Length)
                actions[level](i, count); // do something according to nesting level

            (indices=indices??new List<int>()).Add(i);
            PerformUpdate(destinationIndex, counts, arrays, actions, indices, 1+level);
            indices.RemoveAt(indices.Count-1);
        }
}

此代码以递归方式实现。只要您要定义int[][] arrayoperator *的计算,而operator +和{{1}中的方法名称,MutiplyScalar可以替换为通用数组}}。

因此,我们不会使用AddScalar的委托来控制目的地。相反,我们只是使用Update来实现这一目标。以下是测试用例:

destinationIndex

我们仍然有内联代理,在c#中称为Lambda Expressions。根据您提供的原始代码,嵌套的for循环之间有int[] a=new[] { 1, 2 }, b=new[] { 3, 4, 5 }, c=new[] { 6 }; Action<int, int> m=(index, count) => Debug.Print("index={0}; count={1}", index, count); PerformUpdate(2, new[] { a.Length, b.Length, c.Length }, new[] { a, b, c }, new[] { m, m, m }); 个。但是,我们找不到的信息不是Do something非全球所知的;我们可以看到的最显着的差异是迭代索引和结束数,它们是Updatei, Ij, J。因此,我们只需将这些作为参数传递给k, K来做某事,并且它们对于for循环的每个级别都是可变的。

执行很大程度上取决于Action<int, int>。它存储当前for循环的迭代索引,并传递给下一级递归调用。此外,如果您通过indices计数小于arrays中的Length,则将其视为一个数组,其长度为您传递给的计数。 不要传递负数,也不要传递较大数。可能缺少indices,这只是意味着什么都不做而不是做东西

答案 4 :(得分:0)

这可能会内联它。

interface IFunc<T>
{
    void Invoke(ref T a, ref T b, ref T c);
}

void DoUpdates<TFunc>(TFunc update)
    where TFunc : IFunc<int>
{
    for (int i = 0; i < I; i++)
        for (int j = 0; j < J; j++)
            for (int k = 0; k < K; k++)
                update.Invoke(ref i, ref j, ref k);
}