编译时的常量字段

Posted

技术标签:

【中文标题】编译时的常量字段【英文标题】:Constant field at compiletime 【发布时间】:2014-04-09 09:42:12 【问题描述】:

在c#编译时有什么方法可以区分非常量字段和常量字段吗?

我目前正在开发 c# 代码分析 (FxCop) 规则来检查开发人员的代码是否存在命名不一致。

我一直在寻找一种只针对常量字段的方法。但是它们在编译时是如何声明的呢?有没有像一个标志(我一直在研究“HasDefault”,但这并没有给我太多信息)。

我正在使用 FxCop-API(FxCopSdk.dll 和 Microsoft.Cci.dll)。不使用反射。

总结:如何使用代码分析(FxCop)区分非常量字段和常量字段,以及如何定位常量。

【问题讨论】:

不太清楚你的意思 - 你是不是想通过反射来发现 const int x = 10;static readonly int x = 10; 之间的区别? 不,我不确定您是否熟悉 Visual Studio 中的代码分析(以前称为 FxCop)。这是一种根据各种规则(例如不正确的命名)检查编译代码的机制。欲了解更多信息:msdn.microsoft.com/en-us/library/3z0aeatx.aspx。我想知道的是如何使用这种机制来定位常量。 对我来说听起来更适合 StyleCop,我认为它已经做到了你想要的。私有变量/常量的命名不需要保留在编译的程序集中。 StyleCop 确实做到了这一点,但我被命令使用 FxCop 来实现这一点,因为这些规则不太容易被开发人员忽略。此机制还可以阻止程序编译,“强制”开发人员使用定义的标准。 @Jon Skeet:使用 FxCop API,没有反射。我也在原始问题中添加了这个,谢谢。 【参考方案1】:

进一步研究你提到的FxCop SDK,我发现了一个字段IsLiteral,它基本上意味着一个在编译时指定值的成员。

这对你有用吗?

例如

    public class ClassFieldNamePrefixes : BaseIntrospectionRule
    
        public ClassFieldNamePrefixes() :
            base("ClassFieldNamePrefixes", "TutorialRules.TutorialRules",
                typeof (ClassFieldNamePrefixes).Assembly)
        
        

        public override ProblemCollection Check(Member member)
        
            if (!(member.DeclaringType is ClassNode))
                return this.Problems;

            Field fld = member as Field;
            if (fld == null)
                return this.Problems;

            if (fld.IsLiteral && 
                fld.IsStatic && 
                field.Flags.HasFlag(FieldFlags.HasDefault))
            
            ....
            

            return this.Problems;
        
    

【讨论】:

我似乎找不到针对这些类型修饰符的方法。你知道我怎样才能瞄准他们吗? 我刚刚发现了同样的情况,添加了一个所有常量字段都有的通用标志。感谢您的帮助:) 如何将 IsStatic 与 IsLiteral 一起使用? 作为常量关键字使成员静态? 是的,您也可以添加它。但我也会添加 HasDefault 标志。您可以添加它以便我接受您的答案吗? :)【参考方案2】:

如果我编译一些包含此类的程序集

namespace Foo

    public static class Bar
    
        public int Pointless()
        
            const int Whatever = 1;
            return Whatever;  
        
    

Whatever 在课堂外无法访问。我认为,即使使用反射。事实上,它可能在 IL 中被简化掉了(这是猜想。)

Whatever 的名称纯属风格问题,对编译后的程序集没有影响。如果是 public 字段,例如

namespace Foo

    public static class Bar
    
        public const int Whatever = 1;
    

然后可以通过代码分析来分析名称。


鉴于公共非常量字段已被标记

CA1051: Do not declare visible instance fields

CA2211: Non-constant fields should not be visible

也许你实际上根本不需要区分。

【讨论】:

这实际上是我想要定位的领域。我应该在我的提问中更清楚,对不起!事实上,这确实改变了整个问题,真的很抱歉! 这是很好的信息,但它仍然不能回答我关于能够实际定位常量字段的问题。 @MatthijsL,我唯一能想到的就是反编译NonConstantFieldsShouldNotBeVisible,看看作者是如何做到的。我在任何地方都看不到它的记录。 我确实这样做了,反编译规则并查看是什么。它使用(如回答)field.IsLiteral。此外,几乎没有关于代码分析(FxCop)的文档,在处理此类规则时,这可能是一个真正的错误。【参考方案3】:

我发现了一种针对常量的有点脏的方法。

使用以下将针对他们(但可能会产生误报):

Field field = member as Field;

if (field == null) 
    return null;
if (field.Flags.HasFlag(FieldFlags.HasDefault) && field.IsLiteral && Field.IsStatic)

  // Your code here.

【讨论】:

以上是关于编译时的常量字段的主要内容,如果未能解决你的问题,请参考以下文章

常用的预定义的宏

常量折叠(转载)

枚举类型和位标志

Java——final关键字

常量数据与只读字段

C# 常量,变量,字段,属性,方法