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 =
const string OutputAssembly = 

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: