[英]C#: writing MSIL to add a preprocessor directive
是否有可能在C#中编写MSIL代码,将代码添加预处理程序指令,例如#warning
,如果满足某个条件? 或许这可以通过反思完成,我不知道。
我正在尝试编写一个自定义属性,如果错误地应用于类的方法或属性,将生成编译器警告。 使用现有的Obsolete
属性将不起作用,因为只使用我的自定义属性会导致警告,我不希望这样。 我希望自定义属性构造函数检查条件,如果该条件为true,则导致编译警告。
更新:在回顾了我的问题之后,我认为我所要求的是不可能的,因为我正在混合编译时和运行时约束。 我想我最终将使用一个后期构建任务来检查刚刚构建的DLL,如果条件为真,它会发出错误消息。
我看到这个问题来自你以前的帖子。 错误引用伟大的Jamie Zawinski:“有些人在遇到问题时会想”我知道,我会使用一个属性。“现在他们有两个问题”。
属性仅仅是带外数据,编译为程序集的元数据。 除非程序或工具明确编程为识别特定属性,否则它不会影响程序执行或工具行为。 它需要使用Reflection来实现。
你需要做的是编写自己的工具。 它应该在构建程序集后执行,使用项目的Post-Build步骤。 它需要加载程序集并使用Reflection来迭代程序集中的类型。 对于每种类型,使用Type.GetMethods()迭代方法,并使用MethodInfo.GetCustomAttributes()来发现和构造可能已编程的属性。
您可以使用Type.GetInterfaces()来发现类型实现的接口。 您现在可以在看到存在实现接口方法但缺少属性的方法时抱怨。 并且你的最终目标是:当你看到一个带有一个属性的方法时,你会抱怨它说它实现了一个接口方法,但是类型不再继承它。
如果您发现任何令人反感的事情,请使用Environment.ExitCode使该工具失败。 这需要执行。 顺便说一句:程序员真的很讨厌打破构建。 这可能会鼓励他们虔诚地使用这个属性。 或者它可能会鼓励他们编辑后期构建步骤。
编译器为自定义属性存储两件事:
构造函数仅在应用程序运行时调用,并且有人为您的Assembyl,Type,MethodInfo,ParameterInfo等调用GetCustomAttributes。
您还有其他一些选择:
AttributeUsage
属性指定可以应用该属性的代码项。 简而言之,没有。 预处理指令没有IL表示,因为它们仅作为在编译源文件期间使用的元数据存在。
作为自定义FxCop规则 ,您正在做的事情可能会更好。
你听说过Boo吗? 它有一些有趣的方法可以连接到编译器管道。 一个这样的特性称为语法属性 ,它是实现编译器调用的接口的属性,以便它们可以参与代码生成。
class Person:
[getter(FirstName)]
_fname as string
[getter(LastName)]
_lname as string
def constructor([required] fname, [required] lname):
_fname = fname
_lname = lname
此代码中的属性将为字段生成公共getter,并为构造函数参数进行null检查。 它将最终都在编译的程序集中。
我一直希望这种可扩展性成为C#编译器的一部分。 也许有一天会。 在此之前,您可以使用后编译器,如CciSharp 。 CCiSharp将根据程序集中的特殊属性重写CIL ,就像Boo synctatic属性一样。
鉴于此代码:
class Foo {
[Lazy]
public int Value {
get { return Environment.Ticks; }
}
}
CCiSharp会产生变异基础上的代码LazyAttribute
这样:
class Foo {
int Value$Value; // compiler generated
int Value$Initialized;
int GetValueUncached() {
return Environment.Ticks;
}
public int Value {
get {
if(!this.Value$Initialized) {
this.Value$Value = this.GetValueUncached();
this.Value$Initialized = true;
}
return this.Value$Value;
}
}
CCiSharp基于Common Compiler Infrastructure项目,同样用于在即将推出的.NET Framework 4.0中实现编译后的代码契约 。
所以这就是你如何改变生成的CIL。
但是,# #warning
指令没有CIL表示,它只是一个编译器指令。 要添加此指令,必须改变的不是生成的CIL,而是C#代码本身。 你必须为它实现一个C#解析器。 我认为,如其他回复中所述,最佳选择是创建一个后期构建事件,该事件将反映生成的程序集并发出所需的警告。
我的直觉是,你不能根据自定义属性和条件注入一个#warning指令,因为编译器会在编译时捕获它,它就像鸡和鸡蛋一样,因为自定义属性必须先评估注入一个#warning但为了实现这一点,必须首先执行编译时操作。
希望这会有所帮助,最好的问候,汤姆。
我怀疑答案是否定的,你不能,因为#warning指令是一个CSC的东西(即你指示编译器以某种方式行事)。 在编写原始MISL时,显然,CSC没有混合,因此没有编译器可以指导做某事。
基本上a指令(表示'#warning'是CSC在特定条件下以某种方式表现的指令。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.