Skip to content

Repository files navigation

Verify.ICSharpCode.Decompiler

DiscussionsBuild statusNuGet Status

Extends Verify to allow verification of assemblies via ICSharpCode.Decompiler.

See Milestones for release notes.

Sponsors

Entity Framework Extensions

Entity Framework Extensions is a major sponsor and is proud to contribute to the development this project.

Entity Framework Extensions

Developed using JetBrains IDEs

JetBrains logo.

NuGet

Usage

[ModuleInitializer]publicstaticvoidInit()=>VerifyICSharpCodeDecompiler.Initialize();

snippet source | anchor

Then given the following type:

publicclassTarget:INotifyPropertyChanged{voidOnPropertyChanged([CallerMemberName]string?propertyName=null)=>PropertyChanged?.Invoke(this,new(propertyName));publiceventPropertyChangedEventHandler?PropertyChanged;string?property;publicstring?Property{get=>property;set{property=value;OnPropertyChanged();}}}

snippet source | anchor

Verify Type

[Test]publicasyncTaskTypeDefinitionUsage(){usingvarfile=newPEFile(assemblyPath);vartype=file.Metadata.TypeDefinitions.Single(
_ =>{varfullName=_.GetFullTypeName(file.Metadata);returnfullName.Name=="Target";});awaitVerify(newTypeToDisassemble(file,type));}

snippet source | anchor

Result:

.classpublicautoansibeforefieldinit Target
extends[System.Runtime]System.Object
implements[System.ObjectModel]System.ComponentModel.INotifyPropertyChanged
{
.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
0100000000
)
.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
0100020000
)
.interfaceimpl type [System.ObjectModel]System.ComponentModel.INotifyPropertyChanged
.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
0100000000
)
// Fields.fieldprivatestring'property'.fieldprivateclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler PropertyChanged
.custominstancevoid[System.Runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype[System.Runtime]System.Diagnostics.DebuggerBrowsableState) = (
0100000000000000
)
.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01000000
)
// Methods.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor () cilmanaged {
// Header size: 1// Code size: 8 (0x8).maxstack8IL_0000: ldarg.0IL_0001: callinstancevoid[System.Runtime]System.Object::.ctor()
IL_0006: nopIL_0007: ret
} // end of method Target::.ctor.methodpublicfinalhidebysigspecialnamenewslotvirtualinstancevoid add_PropertyChanged (
class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler 'value'
) cilmanaged {
.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01000000
)
// Header size: 12// Code size: 41 (0x29).maxstack3.localsinit (
[0] class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler,
[1] class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler,
[2] class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler
)
IL_0000: ldarg.0IL_0001: ldfldclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler Target::PropertyChanged
IL_0006: stloc.0// loop start (head: IL_0007)IL_0007: ldloc.0IL_0008: stloc.1IL_0009: ldloc.1IL_000a: ldarg.1IL_000b: callclass[System.Runtime]System.Delegate [System.Runtime]System.Delegate::Combine(class[System.Runtime]System.Delegate, class[System.Runtime]System.Delegate)
IL_0010: castclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler
IL_0015: stloc.2IL_0016: ldarg.0IL_0017: ldfldaclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler Target::PropertyChanged
IL_001c: ldloc.2IL_001d: ldloc.1IL_001e: call !!0[System.Threading]System.Threading.Interlocked::CompareExchange<class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler>(!!0&, !!0, !!0)
IL_0023: stloc.0IL_0024: ldloc.0IL_0025: ldloc.1IL_0026: bne.un.s IL_0007
// end loopIL_0028: ret
} // end of method Target::add_PropertyChanged.methodpublichidebysigspecialnameinstancestring get_Property () cilmanaged {
// Header size: 1// Code size: 7 (0x7).maxstack8IL_0000: ldarg.0IL_0001: ldfldstring Target::'property'IL_0006: ret
} // end of method Target::get_Property.methodprivatehidebysiginstancevoid OnPropertyChanged (
[opt]string propertyName
) cilmanaged {
.param [1] = nullref.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.CallerMemberNameAttribute::.ctor() = (
01000000
)
// Header size: 1// Code size: 26 (0x1a).maxstack8IL_0000: ldarg.0IL_0001: ldfldclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler Target::PropertyChanged
IL_0006: dupIL_0007: brtrue.s IL_000c
IL_0009: popIL_000a: br.s IL_0019
IL_000c: ldarg.0IL_000d: ldarg.1IL_000e: newobjinstancevoid[System.ObjectModel]System.ComponentModel.PropertyChangedEventArgs::.ctor(string)
IL_0013: callvirtinstancevoid[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler::Invoke(object, class[System.ObjectModel]System.ComponentModel.PropertyChangedEventArgs)
IL_0018: nopIL_0019: ret
} // end of method Target::OnPropertyChanged.methodpublicfinalhidebysigspecialnamenewslotvirtualinstancevoid remove_PropertyChanged (
class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler 'value'
) cilmanaged {
.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01000000
)
// Header size: 12// Code size: 41 (0x29).maxstack3.localsinit (
[0] class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler,
[1] class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler,
[2] class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler
)
IL_0000: ldarg.0IL_0001: ldfldclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler Target::PropertyChanged
IL_0006: stloc.0// loop start (head: IL_0007)IL_0007: ldloc.0IL_0008: stloc.1IL_0009: ldloc.1IL_000a: ldarg.1IL_000b: callclass[System.Runtime]System.Delegate [System.Runtime]System.Delegate::Remove(class[System.Runtime]System.Delegate, class[System.Runtime]System.Delegate)
IL_0010: castclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler
IL_0015: stloc.2IL_0016: ldarg.0IL_0017: ldfldaclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler Target::PropertyChanged
IL_001c: ldloc.2IL_001d: ldloc.1IL_001e: call !!0[System.Threading]System.Threading.Interlocked::CompareExchange<class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler>(!!0&, !!0, !!0)
IL_0023: stloc.0IL_0024: ldloc.0IL_0025: ldloc.1IL_0026: bne.un.s IL_0007
// end loopIL_0028: ret
} // end of method Target::remove_PropertyChanged.methodpublichidebysigspecialnameinstancevoid set_Property (
string'value'
) cilmanaged {
// Header size: 1// Code size: 21 (0x15).maxstack8IL_0000: nopIL_0001: ldarg.0IL_0002: ldarg.1IL_0003: stfldstring Target::'property'IL_0008: ldarg.0IL_0009: ldstr"Property"IL_000e: callinstancevoid Target::OnPropertyChanged(string)
IL_0013: nopIL_0014: ret
} // end of method Target::set_Property// Events.event[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler PropertyChanged
{
.addoninstancevoid Target::add_PropertyChanged(class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler)
.removeoninstancevoid Target::remove_PropertyChanged(class[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler)
}
// Properties.propertyinstancestring Property()
{
.getinstancestring Target::get_Property()
.setinstancevoid Target::set_Property(string)
}
} // end of class Target

snippet source | anchor

A string for the type name can also be used:

[Test]publicasyncTaskTypeNameUsage(){usingvarfile=newPEFile(assemblyPath);awaitVerify(newTypeToDisassemble(file,"Target"));}

snippet source | anchor

Verify Method

[Test]publicasyncTaskMethodNameUsage(){usingvarfile=newPEFile(assemblyPath);awaitVerify(newMethodToDisassemble(file,"Target","OnPropertyChanged"));}

snippet source | anchor

Result:

.methodprivatehidebysiginstancevoid OnPropertyChanged (
[opt]string propertyName
) cilmanaged {
.param [1] = nullref.custominstancevoid[System.Runtime]System.Runtime.CompilerServices.CallerMemberNameAttribute::.ctor() = (
01000000
)
// Header size: 1// Code size: 26 (0x1a).maxstack8IL_0000: ldarg.0IL_0001: ldfldclass[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler Target::PropertyChanged
IL_0006: dupIL_0007: brtrue.s IL_000c
IL_0009: popIL_000a: br.s IL_0019
IL_000c: ldarg.0IL_000d: ldarg.1IL_000e: newobjinstancevoid[System.ObjectModel]System.ComponentModel.PropertyChangedEventArgs::.ctor(string)
IL_0013: callvirtinstancevoid[System.ObjectModel]System.ComponentModel.PropertyChangedEventHandler::Invoke(object, class[System.ObjectModel]System.ComponentModel.PropertyChangedEventArgs)
IL_0018: nopIL_0019: ret
} // end of method Target::OnPropertyChanged

snippet source | anchor

Verify Property

[Test]publicasyncTaskPropertyPartsUsage(){usingvarfile=newPEFile(assemblyPath);awaitVerify(newPropertyToDisassemble(file,"Target","Property",PropertyParts.GetterAndSetter));}

snippet source | anchor

Result:

.methodpublichidebysigspecialnameinstancestring get_Property () cilmanaged {
// Header size: 1// Code size: 7 (0x7).maxstack8IL_0000: ldarg.0IL_0001: ldfldstring Target::'property'IL_0006: ret
} // end of method Target::get_Property.methodpublichidebysigspecialnameinstancevoid set_Property (
string'value'
) cilmanaged {
// Header size: 1// Code size: 21 (0x15).maxstack8IL_0000: nopIL_0001: ldarg.0IL_0002: ldarg.1IL_0003: stfldstring Target::'property'IL_0008: ldarg.0IL_0009: ldstr"Property"IL_000e: callinstancevoid Target::OnPropertyChanged(string)
IL_0013: nopIL_0014: ret
} // end of method Target::set_Property

snippet source | anchor

Settings

Starting with version 3.2 the generated IL is normalized by default, to avoid failed tests only because the binary layout has changed:

  • types and members are sorted by name
  • RVA adress comments are stripped

To turn of the sorting, use the DontNormalizeIL setting. It will then decompile IL reflecting the original layout:

[Test]publicasyncTaskBackwardCompatibility(){usingvarfile=newPEFile(assemblyPath);awaitVerify(newTypeToDisassemble(file,"Target")).DontNormalizeIl();}

snippet source | anchor

Icon

Gem designed by Bakunetsu Kaito from The Noun Project.

About

Extends Verify to allow verification of assemblies via ICSharpCode.Decompiler

Resources

Code of conduct

Stars

9 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages