I was asked how to get Mono.Cecil to rewrite PDB files so that VS can step through source when debugging.  Here’s an excerpt of the code I’m using to do this.  It works fine for me!

var assemblyResolver = new DefaultAssemblyResolver();
var assemblyLocation = Path.GetDirectoryName(AssemblyPath);
assemblyResolver.AddSearchDirectory(assemblyLocation);
if (!string.IsNullOrEmpty(HintPath))
{
assemblyResolver.AddSearchDirectory(HintPath);
}
var silverlightAssemblyPath = Environment.ExpandEnvironmentVariables(@”%ProgramFiles%\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\”);
assemblyResolver.AddSearchDirectory(silverlightAssemblyPath);
var readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver };
var writerParameters = new WriterParameters();
var pdbName = Path.ChangeExtension(AssemblyPath, “pdb”);
if (File.Exists(pdbName))
{
var symbolReaderProvider = new PdbReaderProvider();
readerParameters.SymbolReaderProvider = symbolReaderProvider;
readerParameters.ReadSymbols = true;
writerParameters.WriteSymbols = true;
}
var assemblyDefinition = AssemblyDefinition.ReadAssembly(AssemblyPath, readerParameters);
var weaver = new NotifyPropertyChangedWeaver();
weaver.Weave(assemblyDefinition);
assemblyDefinition.Write(AssemblyPath, writerParameters);

 

So I officially hate my life!  I just lost a day of my life trying to get NotifyPropertyChanged weaving working with Mono.Cecil.  It worked brilliantly in .Net, but blew up in Silverlight with a VerificationException (“Operation could destabilize the runtime”) as soon as I tried to invoke my rewritten Property Setters.

I literally combed through every IL instruction in both Reflector and ILDASM and verified everything was as it should be.  In the end the issue was a peculiarity with the CoreCLR as oposed to the full blown CLR.  The CoreCLR requires all locals to be flagged as init even if play by the rules and assign to the local before reading from it.

Here’s the offending IL:

.method public hidebysig specialname instance void set_Property(string 'value') cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
    .maxstack 2
    .locals init (
        [0] string str,
        [1] bool flag)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: call instance string SynerG.Weaving.Tests.DecoratedClass::get_Property()
    L_0007: stloc.0 
    L_0008: ldarg.0 
    L_0009: ldarg.1 
    L_000a: stfld string SynerG.Weaving.Tests.DecoratedClass::<Property>k__BackingField
    L_000f: ldarg.1 
    L_0010: ldloc.0 
    L_0011: call bool [mscorlib]System.Object::Equals(object, object)
    L_0016: stloc.1 
    L_0017: ldloc.1 
    L_0018: brtrue.s L_0028
    L_001a: nop 
    L_001b: ldarg.0 
    L_001c: ldstr "Property"
    L_0021: callvirt instance void [SynerG.Silverlight]SynerG.Notification.NotifyingBase::OnPropertyChanged(string)
    L_0026: nop 
    L_0027: nop 
    L_0028: ret 
}

 You can fix this with a cheeky:

methodBody.InitLocals = true;

Phew.  That’s a day of my life that I’m never going to get back again!