ILSpy icon indicating copy to clipboard operation
ILSpy copied to clipboard

Issue when decompiling private VB.NET WithEvents fields

Open Symbai opened this issue 1 year ago • 1 comments

Input code

.property instance class [System.Windows.Forms]System.Windows.Forms.Timer My_Timer()
{
	.get instance class [System.Windows.Forms]System.Windows.Forms.Timer MyForm.MyClass::get_My_Timer()
	.set instance void MyForm.MyClass::set_My_Timer(class [System.Windows.Forms]System.Windows.Forms.Timer)
}

.method private specialname newslot strict virtual 
	instance class [System.Windows.Forms]System.Windows.Forms.Timer get_My_Timer () cil managed 
{
	.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
		01 00 00 00
	)
	// Method begins at RVA 0x31f4
	// Header size: 1
	// Code size: 7 (0x7)
	.maxstack 8

	IL_0000: ldarg.0
	IL_0001: ldfld class [System.Windows.Forms]System.Windows.Forms.Timer MyForm.MyClass::_My_Timer
	IL_0006: ret
} // end of method MyClass::get_My_Timer

.method private specialname newslot strict virtual 
	instance void set_My_Timer (
		class [System.Windows.Forms]System.Windows.Forms.Timer WithEventsValue
	) cil managed synchronized 
{
	.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
		01 00 00 00
	)
	// Method begins at RVA 0x8428
	// Header size: 12
	// Code size: 55 (0x37)
	.maxstack 2
	.locals init (
		[0] class [mscorlib]System.EventHandler,
		[1] class [System.Windows.Forms]System.Windows.Forms.Timer
	)

	IL_0000: ldarg.0
	IL_0001: ldftn instance void MyForm.MyClass::My_Timer_Elapsed(object, class [mscorlib]System.EventArgs)
	IL_0007: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
	IL_000c: stloc.0
	IL_000d: ldarg.0
	IL_000e: ldfld class [System.Windows.Forms]System.Windows.Forms.Timer MyForm.MyClass::_My_Timer
	IL_0013: stloc.1
	IL_0014: ldloc.1
	IL_0015: brfalse.s IL_001e

	IL_0017: ldloc.1
	IL_0018: ldloc.0
	IL_0019: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Timer::remove_Tick(class [mscorlib]System.EventHandler)

	IL_001e: ldarg.0
	IL_001f: ldarg.1
	IL_0020: stfld class [System.Windows.Forms]System.Windows.Forms.Timer MyForm.MyClass::_My_Timer
	IL_0025: ldarg.0
	IL_0026: ldfld class [System.Windows.Forms]System.Windows.Forms.Timer MyForm.MyClass::_My_Timer
	IL_002b: stloc.1
	IL_002c: ldloc.1
	IL_002d: brfalse.s IL_0036

	IL_002f: ldloc.1
	IL_0030: ldloc.0
	IL_0031: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)

	IL_0036: ret
} // end of method MyClass::set_My_Timer

Erroneous output

private virtual Timer My_Timer
{
	[CompilerGenerated]
	get
	{
		return _My_Timer;
	}
	[MethodImpl(MethodImplOptions.Synchronized)]
	[CompilerGenerated]
	set
	{
		EventHandler value2 = my_Timer_Elapsed;
		Timer my_Timer = _My_Timer;
		if (my_Timer != null)
		{
			my_Timer.Tick -= value2;
		}
		_My_Timer = value;
		my_Timer = _My_Timer;
		if (my_Timer != null)
		{
			my_Timer.Tick += value2;
		}
	}
}

And obviously fails to compile with Error CS0621 '...': virtual or abstract members cannot be private

Note: I opened the assembly and used the "Save code". But its identical to what ILSpy shows me so decompilation is incorrect.

Details

  • Product in use: ILSpy
  • Version in use: 8.2.0.7535
  • Target assembly is a .NET Framework Winforms application

Symbai avatar Dec 08 '23 09:12 Symbai

This is a VB.NET assembly that contains the following field declaration:

Private WithEvents My_Timer As Timer

The VB compiler emits the field as a virtual property to make sure that all events are properly registered/unregistered when the value of the field (re)assigned. Unfortunately this cannot be represented in C# and I am not sure why this is even considered valid in metadata. The best we could do is not emitting the virtual modifier, but that would not help you much, because there will be a lot of other compiler errors anyway.

See also #2602

siegfriedpammer avatar Dec 12 '23 14:12 siegfriedpammer