Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中使用反射检测编译器生成的默认构造函数#_C#_.net_Reflection_Constructor_Default Constructor - Fatal编程技术网

C# 在C中使用反射检测编译器生成的默认构造函数#

C# 在C中使用反射检测编译器生成的默认构造函数#,c#,.net,reflection,constructor,default-constructor,C#,.net,Reflection,Constructor,Default Constructor,我的目标是.NET 3.5 SP1,我用它来验证我的XML文档,在我得到这样一个类之前,一切正常: /// <summary> /// documentation /// </summary> public sealed class MyClass { /// <summary> /// documentation /// </summary> public void Method() { } } // /

我的目标是.NET 3.5 SP1,我用它来验证我的XML文档,在我得到这样一个类之前,一切正常:

/// <summary>
/// documentation
/// </summary>
public sealed class MyClass {
    /// <summary>
    /// documentation
    /// </summary>
    public void Method() {
    }
}
//
///文件
/// 
公共密封类MyClass{
/// 
///文件
/// 
公开作废法(){
}
}
在上面的示例中,据我所知,编译器为我的类生成一个默认构造函数。问题是CommentChecker生成警告,告诉我构造函数缺少注释

我试图修改程序以检测这种特殊情况并忽略它,但我被卡住了,我已经尝试使用
IsDefined(typeof(CompilerGeneratedAttribute),true)
,但这不起作用


简而言之,如何使用反射检测默认构造函数?

无法通过元数据检测自动生成的默认构造函数。您可以通过创建一个包含两个类的类库来测试这一点,一个包含显式默认构造函数,另一个不包含。然后在程序集上运行ildasm:两个构造函数的元数据是相同的


与其尝试检测生成的构造函数,我只需更改程序以允许在任何默认构造函数上丢失文档。大多数文档生成程序,如NDoc和SandcastleGUI,都可以选择向所有默认构造函数添加标准文档;所以根本不需要记录它们。如果代码中有显式的默认构造函数,则可以在构造函数上方加三个斜杠(///),而不加其他内容,以禁用Visual Studio关于缺少文档的警告。

以下代码将返回有关您类型中任何无参数构造函数的信息:

var info = typeof(MyClass).GetConstructor(new Type[] {});
我不知道如何区分默认构造函数和显式指定的无参数构造函数


对于CommentChecker问题,一个可能的解决方法是在需要的地方显式创建无参数构造函数,并对其进行适当的注释。

如果您愿意深入研究IL,则可以获得大部分方法

首先,假设您有一个无参数的实例,您可以像这样获得方法体和方法体的字节(我们将开始构建一个扩展方法来实现这一点):

您可以拒绝任何没有七个字节的方法体

    // Feel free to put this in a constant.
    if (body.Length != 7) return false;
原因将在下面的代码中显而易见

在的第I.8.9.6.6节中,它说明了CLS规则21:

CLS规则21:对象构造函数应调用某个实例 对继承类进行任何访问之前,其基类的构造函数 实例数据。(这不适用于不需要 (有构造函数。)

这意味着在执行任何其他操作之前,必须调用基本构造函数。我们可以在IL中检查这一点。此命令的IL如下所示(我已将字节值放在IL命令之前的括号中):

现在是元数据令牌。需要以元数据令牌的形式与构造函数一起传递方法描述符。这是一个四字节的值,通过上的公开(从中导出
ConstructorInfo

我们可以检查元数据标记是否有效,但因为我们已经检查了方法体的字节数组长度(七个字节),并且我们知道只剩下一个字节需要检查(前两个操作码+四字节元数据标记=六个字节),所以我们不必检查它是否是无参数构造函数;如果有参数,则会有其他操作代码将参数推送到堆栈上,从而扩展字节数组

最后,如果在构造函数中没有执行任何其他操作(表示编译器生成了一个只调用基的构造函数),则在调用元数据令牌之后将发出
ret
指令:

(0x2A) ret
我们可以这样检查:

    return body[6] == 0x2a;
}
需要注意的是,为什么该方法被称为
mightbecharpcilergenerated
,重点是may

假设您有以下课程:

public class Base { }
public class Derived : Base { public Derived() { } }
在没有优化的情况下编译时(通常是
DEBUG
模式),C#编译器将为
派生的
类插入一些(可能是为了帮助调试器),这将导致调用
mightbecharpcilergenerated
返回false

但是,当打开优化时(通常为
RELEASE
模式),C#编译器将发出不带
nop
操作码的七字节方法体,因此它看起来像
Derived
有编译器生成的构造函数,即使它没有


这就是为什么将方法命名为
may
而不是
is
Has
;它表明可能有一种方法需要查看,但不能确定。换句话说,你永远不会得到假阴性结果,但你仍然必须调查是否得到阳性结果。

我担心这是答案,我希望这是可能的,因为StyleCop正确处理了这种情况。StyleCop与原始源代码相反,因此它知道构造函数是隐式的还是显式的。大多数其他静态代码分析工具和大多数文档程序都是针对编译后的程序集工作的,在编译后的程序集中无法区分它们之间的区别。可以请求一个特性,其中“自动”默认构造函数以某种方式得到修饰(使用属性)。字段初始值设定项呢?它们被放入默认的ctor中,并可能导致其大于7bytes@ravyoli这被称为“可能”的另一个原因,因为它的决定完全基于启发式。答案是,没有确定的方法可以做到这一点。
(0x2A) ret
    return body[6] == 0x2a;
}
public class Base { }
public class Derived : Base { public Derived() { } }