编译器在哪些情况下会在C#中生成额外的代码?

huangapple go评论54阅读模式
英文:

In which cases compiler generates additional code in C#?

问题

I've translated the non-code portion of your text:

"所以我一直在使用ILSpy和dnSpy检查一些第三方程序集,注意到了各种编译器生成的类和方法。以下是一些例子:

public Value { get; set; }这样的Getter语法被更改为:

	[CompilerGenerated]
	public int GetValue()
	{
		return this.value;
	}

	[CompilerGenerated]
	public void SetValue(int value)
	{
		this.value = value;
	}

public event EventHandler SomeEvent;这样的事件语法被更改为:

	[CompilerGenerated]
	public void Add(EventHandler someHandler)
	{
		EventHandler eventHandler = this.eventHandler;
		EventHandler eventHandler2;
		do
		{
			eventHandler2 = eventHandler;
			EventHandler value = (EventHandler)Delegate.Combine(eventHandler2, someHandler);
			eventHandler = Interlocked.CompareExchange<EventHandler>(ref this.eventHandler, value, eventHandler2);
		}
		while (eventHandler != eventHandler2);
	}

	[CompilerGenerated]
	public void Remove(EventHandler someHandler)
	{
		EventHandler eventHandler = this.eventHandler;
		EventHandler eventHandler2;
		do
		{
			eventHandler2 = eventHandler;
			EventHandler value = (EventHandler)Delegate.Remove(eventHandler2, someHandler);
			eventHandler = Interlocked.CompareExchange<EventHandler>(ref this.eventHandler, value, eventHandler2);
		}
		while (eventHandler != eventHandler2);
	}

此外,yield return会导致生成实现IEnumerator接口的整个类,复杂的async/await流程会转化为状态机结构等。

所以问题是:我如何在我的程序集中实现上述编译器代码生成行为?

我已经尝试在我的测试程序集中复制这些编译器代码生成,但无论我在哪个.NET框架版本和C#语言版本下构建我的测试应用程序(以Release模式并选中Optimize选项),都会生成漂亮干净的程序集,ILSpy可以将我的所有源代码生成为如果它甚至没有编译过。

更新:在关闭所有ILSpy反编译功能后,我对我的测试程序集获得了类似的结果,但仍然存在event语法。因此,后续问题是:在哪些情况下,反编译工具无法自动反编译C#语言的各种语法结构,以及如何在自己的程序集中实现此类行为?"

英文:

So I've been inspecting some 3rd party assembly with ILSpy & dnSpy and noticed various compiler generated classes and methods. Some examples:

Getter syntax like public Value { get; set; } is changed into:

	[CompilerGenerated]
	public int GetValue()
	{
		return this.value;
	}

	[CompilerGenerated]
	public void SetValue(int value)
	{
		this.value = value;
	}

Event syntax like public event EventHandler SomeEvent; is changed into:

	[CompilerGenerated]
	public void Add(EventHandler someHandler)
	{
		EventHandler eventHandler = this.eventHandler;
		EventHandler eventHandler2;
		do
		{
			eventHandler2 = eventHandler;
			EventHandler value = (EventHandler)Delegate.Combine(eventHandler2, someHandler);
			eventHandler = Interlocked.CompareExchange<EventHandler>(ref this.eventHandler, value, eventHandler2);
		}
		while (eventHandler != eventHandler2);
	}

	[CompilerGenerated]
	public void Remove(EventHandler someHandler)
	{
		EventHandler eventHandler = this.eventHandler;
		EventHandler eventHandler2;
		do
		{
			eventHandler2 = eventHandler;
			EventHandler value = (EventHandler)Delegate.Remove(eventHandler2, someHandler);
			eventHandler = Interlocked.CompareExchange<EventHandler>(ref this.eventHandler, value, eventHandler2);
		}
		while (eventHandler != eventHandler2);
	}

Also, yield return leads to entire generated class that implements IEnumerator interface, complex async/await flows are turned into state machine structs etc.

So the question is: how can I achieve the complier code generation behaviors in my assembly described above?

I've tried to reproduce these compiler code generations in my test assembly but no matter under which .NET framework version and C# language version I've built my test app (in Release mode with Optimize checkmark set) it produced nice and clean assembly where ILSpy is able to produce all my source code as it wasn't even compiled.

UPDATE: After turning off all ILSpy decompilation features I received somewhat similar results for my test assembly but there is still event syntax present. So the follow-up question is: in which cases decompilers fail to automatically decompile various syntax structures of C# language and how to achieve such behavior in own assembly?

答案1

得分: 2

一些编译器功能(例如自动属性或事件处理)在IL代码中没有直接对应项,需要被翻译成比在C#中编写的更复杂的内容。特别是像async/await这样的“现代”编程功能大部分由编译器实现,而不是由运行时实现。因此,这些构造在“底层”生成了相当复杂的代码,通常程序员是看不到的。

反汇编器能否识别这些结构并重新创建原始的简单代码基本上取决于反编译器的质量和年代。较新的功能更不太可能被识别,而更好(可能是非免费的)的反编译器如dotPeek更有可能正确处理这些问题,而简单、便宜的反编译器则不太可能。并不一定“更好”能够正确恢复所有内容,因为我个人经常使用反编译器来检查我的代码翻译成了什么。

此外,许多公共库(特别是在GitHub上具有源代码的库)都包含源代码引用。因此,当您在dotPeek中打开这些程序集时,它将自动下载原始源代码,其中不仅包含完全相同的原始代码,还包括所有的注释。太棒了!当然,这在大多数情况下也适用于您自己的程序集,因为调试信息通常也是可用的。因此,实际上并没有真正的反汇编过程,它只是显示源代码。

英文:

Some compiler features (you name some of them: Automatic properties or event handling) have no direct correspondence in the IL code and need to be translated to something a bit more complex than what you write in C#. Particularly "modern" coding features such as async/await are implemented mostly by the compiler, and not by the runtime. Therefore, such constructs generate quite complex code "under the hood" that the programmer normally doesn't see.

Whether a disassembler is able to recognize these structures and recreate the original, simple code is basically a question of the quality and age of the decompiler. Newer features are less likely to be recognized, and better (and probably non-free) decompilers such as dotPeek are more likely to get things right than simple, cheap decompilers. It's also not necessarily "better", to have everything correctly restored, since personally I often use the decompiler to check what my own code translates into.

Additionally, many public libraries (particularly those with source code on github) come included with a source reference. So when you open these assemblies in dotPeek, it will automatically download the original source, which not only contains the exact original code, but also all the comments. Great! Of course, this most of the time also applies to your own assemblies, since the debug information is usually available, too. So no real disassembling even takes place, it just shows the source.

huangapple
  • 本文由 发表于 2023年5月7日 21:18:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76194172.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定