Function to find a certificate in either the user or the machine store

I wanted a function that would return a certificate, given its serial number, regardless of which store it is in. It has to do almost the same exact thing but twice (once for each store). To keep it encapsulated I wrote the "same thing" bit as a lambda, sort of like a Javascript programmer might.

public X509Certificate FindClientCertificate(string serialNumber)
{
Func<StoreLocation, X509Certificate> find = (location) =>
{
X509Store store = new X509Store(location);
store.Open(OpenFlags.OpenExistingOnly);
IEnumerable certs = store.Certificates.Find(X509FindType.FindBySerialNumber, serialNumber, true);
return certs.OfType<X509Certificate>().FirstOrDefault();
};
return find(StoreLocation.CurrentUser) ?? find(StoreLocation.LocalMachine);
}


Questions:

1. Is the purpose and implementation of this function easier to read with the lambda expression? Or is this utterly confusing?

2. Is there any performance loss or other sort of hidden cost of using a lambda expression as a nested function?

I'm looking forward to C#7 local functions :)

I agree with @JanDotNet that by using a separate method you will gain readability but that's just my subective view.

As you are asking about C#7 stuff I assume that you will use .NET >= 4.6. Starting with .NET 4.6 the X509Store implements IDisposable hence you should enclose the using of the X509Store inside a using block.

Instead of using a concrete type you could use the var type to declare your variables.

This would result in

public X509Certificate FindClientCertificate(string serialNumber)
{
return Find(serialNumber, StoreLocation.CurrentUser) ?? Find(serialNumber, StoreLocation.LocalMachine);
}
private static X509Certificate Find(string serialNumber, StoreLocation location)
{
using (var store = new X509Store(location))
{
store.Open(OpenFlags.OpenExistingOnly);
var certs = store.Certificates.Find(X509FindType.FindBySerialNumber, serialNumber, true);
return certs.OfType<X509Certificate>().FirstOrDefault();
}
}


Is the purpose and implementation of this function easier to read with the lambda expression? Or is this utterly confusing?

IMHO a separate function is more readable:

public X509Certificate FindClientCertificate(string serialNumber)
=> Find(StoreLocation.CurrentUser, serialNumber)
?? Find(StoreLocation.LocalMachine, serialNumber);

private static X509Certificate Find(StoreLocation location, string serialNumber)
{
X509Store store = new X509Store(location);
IEnumerable certs = store.Certificates.Find(X509FindType.FindBySerialNumber, serialNumber, true);
return certs.OfType<X509Certificate>().FirstOrDefault();
}


Local functions make it possible to write succinct code (especially in combination with partial function application as you did), but IMHO it' s harder to read.... probably just a matter of practice ;)

Is there any performance loss or other sort of hidden cost of using a lambda expression as a nested function?

I tested the performance using the following code:

void Main()
{
var swDelegate = new Stopwatch();
var swLocal = new Stopwatch();
var swStatic = new Stopwatch();
var swDelegateWithoutRecreation = new Stopwatch();

Func<int, int, int> calcDelegate = (int otherNumber, int number) => number + otherNumber;

// warm-up
var a = CalcStatic(10);
var b = CalcDelegate(10);
var c = CalcDelegateWithoutRecreation(10, calcDelegate);
var d = CalcLocal(10);

for (int i = 0; i < 10000000; i++)
{
swStatic.Start();
var resStatic = CalcStatic(i);
swStatic.Stop();
swDelegateWithoutRecreation.Start();
var resDelegateWithoutRecreation = CalcDelegateWithoutRecreation(i, calcDelegate);
swDelegateWithoutRecreation.Stop();
swDelegate.Start();
var resDelegate = CalcDelegate(i);
swDelegate.Stop();
swLocal.Start();
var resLocal = CalcLocal(i);
swLocal.Stop();
}

swLocal.ElapsedMilliseconds.Dump("Local");
swDelegate.ElapsedMilliseconds.Dump("Delegate");
swDelegateWithoutRecreation.ElapsedMilliseconds.Dump("Delegate (Without Recreation)");
swStatic.ElapsedMilliseconds.Dump("Static");
}

public int CalcDelegate(int number)
{
Func<int, int> CalcLocal = (int otherNumber) => number + otherNumber;
return CalcLocal(1) + CalcLocal(2);
}

public int CalcLocal(int number)
{
return CalcLocal(1) + CalcLocal(2);

int CalcLocal(int otherNumber) => number + otherNumber;
}

public int CalcDelegateWithoutRecreation(int number, Func<int, int, int> calcFunc)
{
return calcFunc(1, number) + calcFunc(2, number);
}

public int CalcStatic(int number) => CalcStatic(number, 1) + CalcStatic(number, 2);
private static int CalcStatic(int number, int otherNumber) => number + otherNumber;


Result (in Milli seconds):

      Local     Delegate    DelegateWR  Static
266       420         259         249
265       417         258         247
270       424         262         249
272       424         263         251
269       421         262         248
===============================================
Mean: 268,4     421,2       260,8       248,8
108 %     169 %       105 %       100 %


Local functions and delegates (without recreation) are almost as fast as the static version while recreating the delegate each time is ~40% slower.

Note that the performance difference is not noticeable for common programming tasks - so don't care about it.

• I guess the additional time comes from recreating the local function on each call but they are ofter convenient to use and optimizations should be made only if the profiler gives a clear indication to do it anyway :-] Aug 2 '17 at 7:25
• This is what I mean ;-) the local function is probably recreated like any other variable when the outher function gets called. Aug 2 '17 at 7:28
• Ok, I misunderstood your comment. I'll add another test case without recreating the local functions... Aug 2 '17 at 7:30
• Oh, one more thing, Func<int, int> CalcLocal = (int otherNumber) => number + otherNumber; this is not a local function... it's a delegate. Aug 2 '17 at 7:31
• I've added the IL code for both cases. Aug 2 '17 at 7:38

I'm looking forward to C#7 local functions :)

...but they are already there ;-) This means that your lambda can become a local function. I would also put it last and not first. Since it's a method now, the method naming conventions apply, like PascalCasing for its name:

public X509Certificate FindClientCertificate(string serialNumber)
{
return
FindCertificate(StoreLocation.CurrentUser) ??
FindCertificate(StoreLocation.LocalMachine);

X509Certificate FindCertificate(StoreLocation location)
{
X509Store store = new X509Store(location);
store.Open(OpenFlags.OpenExistingOnly);
IEnumerable certs = store.Certificates.Find(X509FindType.FindBySerialNumber, serialNumber, true);
return certs.OfType<X509Certificate>().FirstOrDefault();
};
}


Is the purpose and implementation of this function easier to read with the lambda expression? Or is this utterly confusing?

Yes and no.

Is there any performance loss or other sort of hidden cost of using a lambda expression as a nested function?

There shouldn't be any but if you are not sure then use a profiler... and you'll identify hundredes of other bottlenecks before this lambda will show in any results.

The IL code generated for a delegate and a local function is also different:

When using a delegate:

FindClientCertificate:
IL_0000:  newobj      UserQuery+<>c__DisplayClass1_0..ctor
IL_0005:  stloc.0     // CS$<>8__locals0 IL_0006: ldloc.0 // CS$<>8__locals0
IL_0007:  ldarg.1
IL_0008:  stfld       UserQuery+<>c__DisplayClass1_0.serialNumber
IL_000D:  nop
IL_000E:  ldloc.0     // CS$<>8__locals0 IL_000F: ldftn UserQuery+<>c__DisplayClass1_0.<FindClientCertificate>b__0 IL_0015: newobj System.Func<System.Security.Cryptography.X509Certificates.StoreLocation,System.Security.Cryptography.X509Certificates.X509Certificate>..ctor IL_001A: stloc.1 // find IL_001B: ldloc.1 // find IL_001C: ldc.i4.1 IL_001D: callvirt System.Func<System.Security.Cryptography.X509Certificates.StoreLocation,System.Security.Cryptography.X509Certificates.X509Certificate>.Invoke IL_0022: dup IL_0023: brtrue.s IL_002D IL_0025: pop IL_0026: ldloc.1 // find IL_0027: ldc.i4.2 IL_0028: callvirt System.Func<System.Security.Cryptography.X509Certificates.StoreLocation,System.Security.Cryptography.X509Certificates.X509Certificate>.Invoke IL_002D: stloc.2 IL_002E: br.s IL_0030 IL_0030: ldloc.2 IL_0031: ret  When using a local function: FindClientCertificate2: IL_0000: ldloca.s 00 // CS$<>8__locals0
IL_0002:  initobj     UserQuery.<>c__DisplayClass2_0
IL_0008:  ldloca.s    00 // CS$<>8__locals0 IL_000A: ldarg.1 IL_000B: stfld UserQuery+<>c__DisplayClass2_0.serialNumber IL_0010: nop IL_0011: ldc.i4.1 IL_0012: ldloca.s 00 // CS$<>8__locals0
IL_0014:  call        UserQuery.<FindClientCertificate2>g__FindCertificate2_0
IL_0019:  dup
IL_001A:  brtrue.s    IL_0025
IL_001C:  pop
IL_001D:  ldc.i4.2
IL_001E:  ldloca.s    00 // CS\$<>8__locals0
IL_0020:  call        UserQuery.<FindClientCertificate2>g__FindCertificate2_0
IL_0025:  stloc.1
IL_0026:  br.s        IL_0028
IL_0028:  ldloc.1
IL_0029:  ret

<FindClientCertificate2>g__FindCertificate2_0:
IL_0000:  nop
IL_0001:  ldarg.0
IL_0002:  newobj      System.Security.Cryptography.X509Certificates.X509Store..ctor
IL_0007:  stloc.0     // store
IL_0008:  ldloc.0     // store
IL_0009:  ldc.i4.4
IL_000A:  callvirt    System.Security.Cryptography.X509Certificates.X509Store.Open
IL_000F:  nop
IL_0010:  ldloc.0     // store
IL_0011:  callvirt    System.Security.Cryptography.X509Certificates.X509Store.get_Certificates
IL_0016:  ldc.i4.5
IL_0017:  ldarg.1
IL_0018:  ldfld       UserQuery+<>c__DisplayClass2_0.serialNumber
IL_001D:  ldc.i4.1
IL_001E:  callvirt    System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Find
IL_0023:  stloc.1     // certs
IL_0024:  ldloc.1     // certs
IL_0025:  call        System.Linq.Enumerable.OfType<X509Certificate>
IL_002A:  call        System.Linq.Enumerable.FirstOrDefault<X509Certificate>
IL_002F:  stloc.2
IL_0030:  br.s        IL_0032
IL_0032:  ldloc.2
IL_0033:  ret

<>c__DisplayClass1_0.<FindClientCertificate>b__0:
IL_0000:  nop
IL_0001:  ldarg.1
IL_0002:  newobj      System.Security.Cryptography.X509Certificates.X509Store..ctor
IL_0007:  stloc.0     // store
IL_0008:  ldloc.0     // store
IL_0009:  callvirt    System.Security.Cryptography.X509Certificates.X509Store.get_Certificates
IL_000E:  ldc.i4.5
IL_000F:  ldarg.0
IL_0010:  ldfld       UserQuery+<>c__DisplayClass1_0.serialNumber
IL_0015:  ldc.i4.1
IL_0016:  callvirt    System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Find
IL_001B:  stloc.1     // certs
IL_001C:  ldloc.1     // certs
IL_001D:  call        System.Linq.Enumerable.OfType<X509Certificate>
IL_0022:  call        System.Linq.Enumerable.FirstOrDefault<X509Certificate>
IL_0027:  stloc.2
IL_0028:  br.s        IL_002A
IL_002A:  ldloc.2
IL_002B:  ret


As you can see it is compiled as a member of an anonymous type c__DisplayClass1_0.

• That formatting looks much cleaner! Probably I would prefer that over a separate static function. Aug 2 '17 at 7:21
• I can't read IL, but it seems, that the anonymous class is created each time the method is called - therefore that (creating one short-living object) is the only overhead when using local functions, isn't it? Aug 2 '17 at 7:59
• @JanDotNet me either but it looks like the wrapper for a delegate is created on each call whereas the local function is compiled and reused. This would explain the much longer code for it and also the difference in performance. Aug 2 '17 at 11:00