[Source: http://geekswithblogs.net/EltonStoneman]

In code with lots of lambda expressions, you may trigger a false positive for the Code Analysis rule CA1502 “AvoidExcessiveComplexity”. The rule calculates cyclomatic complexity using the logic in Microsoft.FxCop.Sdk.MethodMetrics, which enumerates the instruction set and increments complexity count when it finds one of a given set of opcodes.

The rule was triggered code which uses the Fluent DAL approach to populate a composite entity:

public static Entity GetEntity(int entityId)

{

//populate basic details:

Entity entity = Fluently.Load<Entity>().With<EntityMap>()

.From<GetEntity>(i => i.Id = entityId,

x => x.Execute());

//load child entities:

if (entity.IsKnown)

{

entity.Address = Fluently.Load<Address>().With<AddressMap>()

.From<GetEntityAddresses>(i => i.Id = entityId,

x => x.Execute());

entity.Contact = Fluently.Load<Contact>().With<ContactMap>()

.From<GetEntityContacts>(i => i.Id = entityId,

x => x.Execute());

}

else

{

//more of the same

The method in question had a single if/else branch, no other conditional logic, but 7 fluent calls totalling 12 lambdas. I calculate the cyclomatic complexity to be 2, and NDepend agrees. FxCop tells me the complexity is 26.

I stripped this down to a much simpler sample and found the same issue:

public void CCCheck2()

{

Fluently.Load().With().From(i => i.ToString(), x => x.ToString());

Fluently.Load().With().From(i => i.ToString(), x => x.ToString());

Fluently.Load().With().From(i => i.ToString(), x => x.ToString());

}

– this gives a CC of 13, although it has no conditional logic at all.

The answer’s in the IL – the lambdas are emitted as private static classes and executed using an instance which is lazy-loaded:

IL_000b: ldsfld class [System.Core]System.Func`2<int32,string> FxCopCC.LambdaSample::’CS$<>9__CachedAnonymousMethodDelegate6′

IL_0010: brtrue.s IL_0025

IL_0012: ldnull

IL_0013: ldftn string FxCopCC.LambdaSample::'<CCCheck>b__0′(int32)

IL_0019: newobj instance void class [System.Core]System.Func`2<int32,string>::.ctor(object,

native int)

IL_001e: stsfld class [System.Core]System.Func`2<int32,string> FxCopCC.LambdaSample::’CS$<>9__CachedAnonymousMethodDelegate6′

IL_0023: br.s IL_0025

br and brtrue are transfer of control statements, so every lambda expression actually causes a branch – where the IL checks to see if there’s a cached instance of the delegate, or whether it needs to instantiate one – and a return. The complexity rating is correct for the IL, as 1 + 2x(number of lambdas).

But cyclomatic complexity is a measure of readability, so the additional branches in the IL should be irrelevant. The short term solution is to suppress the message on methods with heavy lambda usage. A longer term option is an alternative rule which uses a different calculation.

A side point is that the IL isn’t aggressively optimised by the compiler – lambdas with identical code are generated as separate private classes, each with their own lazy-loading check, so to avoid that overhead lambdas which are reused can be centralised:

private Func<int, string> GetInitialise()

{

return new Func<int,string>(i => i.ToString());

}