为什么IsLiteral对于小数返回false?

时间:2018-07-31 07:00:06

标签: c# reflection decimal const

以下程序将使用IsLiteral

打印字段以及字段是否恒定。
public static class Program
{
    public static void Main(string[] args)
    {
        foreach (var field in typeof(Program).GetFields())
        {
            System.Console.WriteLine(field.Name + " IsLiteral: " + field.IsLiteral);
        }

        System.Console.ReadLine();
    }

    public const decimal DecimalConstant = 99M;
    public const string StringConstant = "StringConstant";
    public const int IntConstant = 1;
    public const double DoubleConstant = 1D;
}

它对所有类型均正常工作,除了decimal将返回false。

有人可以解释这种行为吗?还有没有更好的方法来查看字段是否恒定?

1 个答案:

答案 0 :(得分:5)

运行时角度来看,这不是一个常数-因为CLR基本上不了解decimal;它不是原始类型。这就是为什么您也不能在属性中使用小数。

如果查看字段的IL,您可以看到它的作用:

.field public static initonly valuetype [mscorlib]System.Decimal DecimalConstant
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor
  (uint8, uint8, uint32, uint32, uint32) =
  (01 00 00 00 00 00 00 00 00 00 00 00 63 00 00 00 00 00) 
.field public static literal string StringConstant = "StringConstant"
.field public static literal int32 IntConstant = int32(0x00000001)
.field public static literal float64 DoubleConstant = float64(1.)

请注意其他常量 的IL如何包含literal,但DecimalConstant没有。相反,它只是一个应用了属性的只读字段。该属性允许其他编译器将字段视为常量并知道该值-例如,它可以出现在其他const表达式中。

然后有一个类型初始化程序,用于在执行时设置字段值:

.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  ldc.i4.s   99
  IL_0002:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0007:  stsfld     valuetype [mscorlib]System.Decimal Program::DecimalConstant
  IL_000c:  ret
} // end of method Program::.cctor

同样,仅在DecimalConstant中存在,因为运行时直接处理其他字段。