Inconsistent result when comparing Actions/Funcs

时间:2018-02-01 18:30:22

标签: c# comparison func

I have been trying to cache the results of certain Actions and Funcs. For that purpose I am storing the Actions/Funcs in a Dictionary with their respective result.

Whilst doing this I stumbled upon something unexpected (example is simplified):

        var lstActions = new List<Action>();

        for (int i = 0; i < 2; i++)
        {
            lstActions.Add(() => { });
        }

        bool bEqual = lstActions[0] == lstActions[1]; // Result = true

--

        var lstActions = new List<Action>();

        lstActions.Add(() => { });
        lstActions.Add(() => { });

        bool bEqual = lstActions[0] == lstActions[1]; // Result = false

Can anyone explain why the results are different?

2 个答案:

答案 0 :(得分:2)

You're seeing implementation details about how the compiler transforms lambda expressions into delegates that point to compiler-generated methods.

This behavior may change due to changes in the compiler, debug vs. release builds, or changes in the contents of any of the lambdas.

To explain your current behavior:

Every lambda that appears in source is compiled to a separate method. Therefore, your second example generates two methods (which happen to have identical bodies), and the delegates are not the same.

Your first example only has one lambda in the source, so it compiles to a single method. Because the lambda doesn't use any local variables, it doesn't generate a closure class, so the both the Method and Target properties of the delegates are the same.

答案 1 :(得分:0)

The compiler tries to minimize the amount of delegate objects it creates. To this end it often caches instances where this is possible.

Since your first example you define a single lambda and it does not capture any loop variables, a single delegate instance will suffice.

In the second example, you defined two different anonymous methods, the compiler will not check that their code is identical as this is a rare case, and will create two delegate instances.

This is however an implementation detail of the compiler and I would not rely on it in any way.