## UnconstrainedMelody with .Net 4

We wanted to include Unconstrained Melody in our .Net project because it provides strongly typed versions of Enum.Parse and Enum.TryParse. (see here and here for more information)

To achieve this, it uses a tool (included in the package) called ConstraintChanger, which performs a bit of MSIL magic on the compiled assembly.

Since our project is on .Net 4.x, but the library was written in the times of .Net 2, some adjustments needed to be made.

First, the Visual Studio (2010, 2012) solution upgrade kicks in and converts solution and projects to the current VS version. Next, we need to change the projects to compile to the .Net 4 Framework.

Hitting Build caused the build to fail for two reasons:

• ConstraintChanger did not find the generated UnconstrainedMelody assembly, *or* the required target directory did not exist
• The UnconstrainedMelody.Test test project refers to the “rewritten” UnconstrainedMelody assembly which does not yet exist.

Since the ConstraintChanger source code references the assemblies with relative paths, and I did not want to figure out where it executes etc., I modified Program.cs to use absolute paths:

private const string InputAssembly =
@"C:\path\to\UnconstrainedMelody\UnconstrainedMelody\bin\Debug\UnconstrainedMelody.dll";
const string OutputAssembly =
@"C:\path\to\UnconstrainedMelody\UnconstrainedMelody\Rewritten\UnconstrainedMelody.dll";

Next, the MS SDK path needs to be updated to refer to ProgramFilesX86 and V7.0A:

string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
string sdkDirectory = Path.Combine(programFiles, @"Microsoft SDKs\Windows\v7.0A\bin");

and the path to the .Net 4 framework as well

string framework2Directory = Path.Combine(windows, @"..\Microsoft.NET\Framework\v4.0.30319");

After building the library and creating the directory C:\path\to\UnconstrainedMelody\UnconstrainedMelody\Rewritten the program can be executed.

Next, I updated the UnconstrainedMelody reference in the test project, and the tests succeeded.

I noticed that the library does not contain case-insensitive versions of Enum.Parse and Enum.TryParse, so I added to EnumInternals.cs:

internal static readonly IList<string> NamesLC;
NamesLC = new ReadOnlyCollection<string>(Names.Select(n => n.ToLower()).ToList());

and to Enums.cs:

public static T ParseName<T>(string name, bool ignoreCase)
where T : struct, IEnumConstraint
{
T value;
if (!TryParseName(name, ignoreCase, out value))
{
throw new ArgumentException("Unknown name", "name");
}
return value;
}
public static bool TryParseName<T>(string name, bool ignoreCase, out T value)
where T : struct, IEnumConstraint
{
if (string.IsNullOrEmpty(name))
{
value = default(T);
return false;
}
int index = ignoreCase
? EnumInternals<T>.NamesLC.IndexOf(name.ToLower())
: EnumInternals<T>.Names.IndexOf(name);
if (index == -1)
{
value = default(T);
return false;
}
value = EnumInternals<T>.Values[index];
return true;
}

Note that every change in the UM library needs both compilation and patching (by ConstraintChanger) for the library to work correctly.