A little Background For quite some time now, it’s been possible to merge multiple .NET assemblies into a single assembly using ILMerge in Visual Studio 2008. This is especially helpful when writing wrapper assemblies for 3rd-party libraries where it’s desirable to minimize the number of assemblies for distribution. During the merge process, ILMerge will take a set of assemblies and merge them into a single assembly. The resulting assembly can be either an executable or a DLL and is identified as the primary assembly. Issue During a recent project, I discovered using ILMerge to merge assemblies containing lambda expressions in Visual Studio 2010 is resulting in invalid primary assemblies. The code below is not where the initial issue was identified, I will merely use it to illustrate the problem at hand. In order to describe the issue, I created a console application and a class library for calculating a few math functions utilizing lambda expressions. The code is available for download at the bottom of this blog entry. MathLib.cs using System;
namespace MathLib
{
public static class MathHelpers
{
public static Func<double, double, double> Hypotenuse =
(x, y) => Math.Sqrt(x * x + y * y);
static readonly Func<int, int, bool> divisibleBy = (int a, int b) => a % b == 0;
public static bool IsPrimeNumber(int x)
{
{
for (int i = 2; i <= x / 2; i++)
if (divisibleBy(x, i))
return false;
return true;
};
}
}
}
Program.cs
using System;
using MathLib;
namespace ILMergeLambdasConsole
{
class Program
{
static void Main(string[] args)
{
int n = 19;
if (MathHelpers.IsPrimeNumber(n))
{
Console.WriteLine(n + " is prime");
}
else
{
Console.WriteLine(n + " is not prime");
}
Console.ReadLine();
}
}
}
Not surprisingly, the preceding code compiles, builds and executes without error prior to running the ILMerge tool.
ILMerge Setup
In order to utilize ILMerge, the following changes were made to the project.
The MathLib.dll assembly was built in release configuration and copied to the MathLib folder. The following folder hierarchy was used for this example:
The project file for ILMergeLambdasConsole project file was edited to add the ILMerge post-build configuration. The following lines were added near the bottom of the project file:
<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'">
<Exec Command=""..\..\lib\ILMerge\Ilmerge.exe" /ndebug /out:@(MainAssembly)
"@(IntermediateAssembly)" @(ReferenceCopyLocalPaths->'"%(FullPath)"', ' ')" />
<Delete Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
The ILMergeLambdasConsole project was modified to reference the MathLib.dll located in the MathLib folder above.
ILMerge and ILMerge.exe.config was copied into the ILMerge folder shown above. The contents of ILMerge.exe.config are:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/>
</startup>
</configuration>
Post-ILMerge
After compiling and building, the MathLib.dll assembly will be merged into the ILMergeLambdasConsole executable. Unfortunately, executing ILMergeLambdasConsole.exe now results in a crash. The ILMerge documentation recommends using PEVerify.exe to validate assemblies after merging. Executing PEVerify.exe against the ILMergeLambdasConsole.exe assembly results in the following error:
Further investigation by using Reflector reveals the divisibleBy method in the MathHelpers class looks a bit questionable after the merge.
Prior to using ILMerge, the same divisibleBy method appeared as the following in Reflector:
It’s pretty obvious something has gone awry during the merge process. However, this is only occurring when building within the Visual Studio 2010 environment. The same code and configuration built within Visual Studio 2008 executes fine. I’m still investigating the issue. If anyone has already experienced this situation and solved it, I would love to hear from you. However, as of right now, it looks like something has gone terribly wrong when executing ILMerge against assemblies containing Lambdas in Visual Studio 2010.
Solution Files ILMergeLambdaExpression