C#学习教程:在C#中使用反射检测编译器生成的默认构造函数工作正常,直到我像这样进入类://////documentation///publicsealedclassMyClass{//////documentation///publicvoidMethod(){}}在上面的例子中,到目前为止据我所知,编译器为我的类生成了一个默认构造函数。问题是CommentChecker会生成警告,告诉我构造函数缺少注释。我正在尝试修改程序以检测这种特殊情况并忽略它,但我被卡住了,我已经尝试过IsDefined(typeof(CompilerGeneratedAttribute),true)但它没有用。简而言之,如何使用反射检测默认构造函数?无法通过元数据检测到自动生成的默认构造函数。您可以通过创建一个包含两个类的类库来对此进行测试,一个类具有显式默认构造函数,一个没有。然后在程序集上运行ildasm:两个构造函数的元数据相同。我只是更改了程序以允许缺少任何默认构造函数的文档,而不是尝试检测生成的构造函数。大多数文档生成程序,例如NDoc和SandcastleGUI,都可以选择向所有默认构造函数添加标准文档;所以根本不需要记录它们。如果您的代码中有显式默认构造函数,您可以在构造函数上方放置三个斜杠(///)——其他任何东西——以禁用VisualStudio关于缺少文档的警告。如果您愿意在IL中挖掘一点,您可以在那里获得大部分内容。首先,假设您有一个您知道没有参数的ConstructorInfo实例,您可以像这样获取方法主体和方法主体的字节(我们将开始构建扩展方法来执行此操作):publicstaticboolMightBeCSharpCompilerGenerated(thisConstructorInfoconstructor){//验证参数。如果(构造函数==null)抛出新的ArgumentNullException(“构造函数”);//如果方法是静态的,抛出异常。if(constructor.IsStatic)thrownewArgumentException("构造函数参数必须是一个"+"实例构造函数。","constructor");//获取body.byte[]body=constructor.GetMethodBody().GetILAsByteArray();您可以拒绝任何没有七个字节的方法体。//随意把它放在常量中。如果(body.Length!=7)返回false;原因将在下面的代码中显而易见。在ECMA-335的I.8.9.6.6部分(公共语言基础设施(CLI)分区I到VI)中,它声明了CLS规则21:CLS规则21:在对继承的实例数据进行任何访问之前,对象构造函数实例构造函数之一应该调用它的基类。(这不适用于不需要构造函数的值类型。)这意味着必须先调用基础构造函数才能完成任何其他操作。我们可以在IL中检查这个。这样的IL看起来像这样(我将字节值放在IL命令之前的括号中)://在堆栈上加载“this”,因为实例方法的第一个参数//总是“this”。(0x02)ldarg.0//没有加载任何参数,但会解释元数据令牌。(0x28)call我们现在可以开始检查字节://检查前两个字节,如果它们不是加载//第一个参数然后调用,则不是//对构造函数的调用。如果(身体[0]!=0x02||身体[1]!=0x28)返回假;现在是元数据令牌。调用指令需要方法描述符以元数据标记的形式与构造函数一起传递。这是一个四字节值,通过MemberInfo类(ConstructorInfo派生自该类)的MetadataToken属性公开。我们可以检查元数据令牌是否有效,但由于我们已经检查了方法主体的字节数组的长度(七个字节),而且我们知道只剩下一个字节要检查(前两个操作码)+四个字节元数据标记=六个字节),我们不必检查它是否是无参数构造函数;如果它有参数,还有其他操作码将参数压入堆栈,扩展字节数组。最后,如果在构造函数中没有做任何其他事情(表明编译器生成的构造函数除了调用基ret之外什么都不做),在调用元数据标记之后发出ret指令:(0x2A)ret我们可以这样做Check:returnbody[6]==0x2a;注意为什么该方法被称为MightBeCSharpCompilerGenerated并强调Might。假设你有以下类:publicclassBase{}publicclassDerived:Base{publicDerived(){}}在没有优化的情况下编译时(通常是DEBUG模式),C#编译器会插入一些nop代码(可能是为了协助调试器),这会导致对MightBeCSharpCompilerGenerated的调用返回false。但是,当优化打开时(通常是RELEASE模式),C#编译器会发出没有nop操作码的七字节方法体,因此看起来Derived有一个编译器生成的构造函数,即使它没有。这就是为什么该方法被命名为Might而不是Is或Has的原因;它表明可能有一种方法可以查看,但不能确定。换句话说,你永远不会得到假阴性,但你仍然需要调查你是否得到了阳性结果。以下代码将返回类型中任何无参数构造函数的信息:varinfo=typeof(MyClass).GetConstructor(newType[]{});.CommentChecker问题的一种可能解决方法是在需要的地方显式创建一个无参数构造函数并适当地对其进行注释。以上就是C#学习教程:在C#中使用反射检测编译器生成的默认构造函数。如果对你有用,需要了解更多C#学习教程,希望大家多加关注——本文来自网络合集,不代表立场,如涉及侵权,请点击有权联系管理员删除。如需转载请注明出处:
