zoukankan      html  css  js  c++  java
  • Effiective C#:ITEM2:优先使用readonly而不是const

    C#中常量有两个不同版本:编译时刻常量和运行时常量。它们的行为相去甚远,使用错误版本的常量会
    损失程序性能或者出错。两个问题都是我们不愿见到的,但如果一定要选择,一个速度略慢但正确的程
    序比一个快速却出错的程序要好的多。所以你应该优先选择运行时常量而不是编译时刻常量。编译时刻
    常量会稍快一点,但和运行时常量相比柔韧性却差很多。只有当性能异常重要并且常量的值永远不会随
    时间改变的时候才用编译时刻常量

    运行时常量使用readonly关键字来声明。编译时刻常量用const关键字。

    编译时刻常量被你的对象代码中的值替代

    运行时常量在运行时刻确定。当引用一个[引用了readonly变量的只读常量]而不是[值]的时候

     这个差别给我们使用两中类型的常量带来几个限制。编译时刻常量只能用作简单类型(内建整型浮点型
    ),每局或者字符串。这些类型是你可以在初始化器重赋予有意义常量值的仅有的几种类型,也是编译
    器生成的IL中能被替换为文字值的仅有类型。你不能使用new操作符初始化编译时刻常量,即便类型被初
    始化为值类型

    // Does not compile, use readonly instead:
    private const DateTime _classCreation = new
    DateTime( 2000, 1, 1, 0, 0, 0 );
    
    readonly值夜是常量,他们不能在构造器执行之后被修改。运行时常量有更多的柔韧性。
    有一点,运行时常量可以是任何类型。
    你一定要在一个构造器中初始化他们,或者你可以使用一个初始化器。
     
    

    Item 2: Prefer readonly to const

    C# has two different versions of constants: compile-time constants and runtime
    constants.
    They have very different behaviors, and using the wrong one will cost
    you performance or correctness. Neither problem is a good one to have, but if
    you must pick one, a slower, correct program is better than a faster, broken
    program. For that reason, you should prefer runtime constants over compile-time
    constants. Compile-time constants are slightly faster, but far less flexible,
    than runtime constants.
    Reserve the compile-time constants for when performance is critical and the
    value of the constant will never change over time
    .

    You declare runtime constants with the readonly keyword. Compile-time constants
    are declared
    with the const keyword:

    // Compile time constant:

    public const int _Millennium = 2000;

     

    // Runtime constant:

    public static readonly int _ThisYear = 2004;

     

    The differences in the behavior of compile-time and runtime constants follow
    from how they are accessed. A compile-time constant is replaced with the value
    of that constant in your object code.
    This construct:

    if ( myDateTime.Year == _Millennium )

     

    compiles to the same IL as if you had written this:

    if ( myDateTime.Year == 2000 )

     

    Runtime constants are evaluated at runtime. The IL generated when you reference
    a read-only constant references the readonly variable, not the value.

    This distinction places several restrictions on when you are allowed to use
    either type of constant. Compile-time constants can be used only for primitive
    types
    (built-in integral and floating-point types), enums, or strings. These
    are the only types that enable you to assign meaningful constant values in
    initializers. These primitive types are the only ones that can be replaced
    with literal values in the compiler-generated IL. The following construct does
    not compile. You cannot initialize a compile-time constant using the new
    operator, even when the type being initialized is a value type:

    // Does not compile, use readonly instead:

    private const DateTime _classCreation = new

     DateTime( 2000, 1, 1, 0, 0, 0 );

     

    Compile-time constants are limited to numbers and strings. Read-only values
    are also constants, in that they cannot be modified after the constructor
    has executed.
    But read-only values are different, in that they are assigned
    at runtime. You have much more flexibility in working with runtime constants.
    For one thing, runtime constants can be any type. You must initialize them
    in a constructor, or you can use an initializer. You can make readonly values
    of the DateTime structures; you cannot create DateTime values with const.

    You can use readonly values for instance constants, storing different values
    for each instance of a class type. Compile-time constants are, by definition,
    static constants.

    The most important distinction is that readonly values are resolved at runtime.
    The IL generated when you reference a readonly constant references the readonly
    variable, not the value.
    This difference has far-reaching implications on
    maintenance over time. Compile-time constants generate the same IL as though
    you've used the numeric constants in your code, even across assemblies: A
    constant in one assembly is still replaced with the value when used in another
    assembly.

    The way in which compile-time and runtime constants are evaluated affects runtime
    compatibility.
    Suppose you have defined both const and readonly fields in an assembly
    named Infrastructure:

    public class UsefulValues

    {

     public static readonly int StartValue = 5;

     

     public const int EndValue = 10;

    }

     

    In another assembly, you reference these values:

    for ( int i = UsefulValues.StartValue;

     i < UsefulValues.EndValue;

     i++ )

     Console.WriteLine( "value is {0}", i );

     

    If you run your little test, you see the following obvious output:

    Value is 5

    Value is 6

    ...

    Value is 9

     

    Time passes, and you release a new version of the Infrastructure assembly
    with the following changes:

    public class UsefulValues

    {

     public static readonly int StartValue = 105;

     

     public const int EndValue = 120;

    }

     

    You distribute the Infrastructure assembly without rebuilding your Application
    assembly. You expect to get this:

    Value is 105

    Value is 106

    ...

    Value is 119

     

    In fact, you get no output at all. The loop now uses the value 105 for its start
    and 10 for its end condition. The C# compiler placed the const value of 10 into
    the Application assembly instead of a reference to the storage used by EndValue.
    Contrast that with the StartValue value. It was declared as readonly: It gets
    resolved at runtime.
    Therefore, the Application assembly makes use of the new
    value without even recompiling the Application assembly; simply installing an
    updated version of the Infrastructure assembly is enough to change the behavior
    of all clients using that value. Updating the value of a public constant should
    be viewed as an interface change. You must recompile all code that references
    that constant. Updating the value of a read-only constant is an implementation
    change; it is binary compatible with existing client code. Examining the MSIL
    for the previous loop shows you exactly why this happens:

    IL_0000: ldsfld     int32 Chapter1.UsefulValues::StartValue

    IL_0005: stloc.0

    IL_0006: br.s       IL_001c

    IL_0008: ldstr      "value is {0}"

    IL_000d: ldloc.0

    IL_000e: box        [mscorlib]System.Int32

    IL_0013: call       void [mscorlib]System.Console::WriteLine

        (string,object)

    IL_0018: ldloc.0

    IL_0019: ldc.i4.1

    IL_001a: add

    IL_001b: stloc.0

    IL_001c: ldloc.0

    IL_001d: ldc.i4.s   10

    IL_001f: blt.s      IL_0008

     

    You can see that the StartValue is loaded dynamically at the top of the MSIL listing.
    But the end condition, at the end of the MSIL, is hard-coded at 10.

    On the other hand, sometimes you really mean for a value to be determined at compile
    time.
    For example, consider a set of constants to mark different versions of an object
    in its serialized form (see Item 25). Persistent values that mark specific versions
    should be compile-time constants; they never change. Thecurrent version should be a
    runtime constant, changing with each release.

    private const int VERSION_1_0 = 0x0100;

    private const int VERSION_1_1 = 0x0101;

    private const int VERSION_1_2 = 0x0102;

    // major release:

    private const int VERSION_2_0 = 0x0200;

     

    // check for the current version:

    private static readonly int CURRENT_VERSION =

     VERSION_2_0;

     

    You use the runtime version to store the current version in each saved file:

    // Read from persistent storage, check

    // stored version against compile-time constant:

    protected MyType( SerializationInfo info,

     StreamingContext cntxt )

    {

     int storedVersion = info.GetInt32( "VERSION" );

     switch ( storedVersion )

     {

     case VERSION_2_0:

        readVersion2( info, cntxt );

        break;

     case VERSION_1_1:

        readVersion1Dot1( info, cntxt );

        break;

     

     // etc.

     }

    }

     

    // Write the current version:

    [ SecurityPermissionAttribute( SecurityAction.Demand,

     SerializationFormatter =true ) ]

    void ISerializable.GetObjectData( SerializationInfo inf,

        StreamingContext cxt )

    {

     // use runtime constant for current version:

     inf.AddValue( "VERSION", CURRENT_VERSION );

     

     // write remaining elements...

    }

     

    The final advantage of using const over readonly is performance: Known
    constant values can generate slightly more efficient code than the variable
    accesses necessary for readonly values. However, any gains are slight and
    should be weighed against the decreased flexibility.
    Be sure to profile
    performance differences before giving up the flexibility.

    const must be used when the value must be available at compile times:
    attribute parameters and enum definitions, and those rare times when
    you mean to define a value that does not change from release to release.
    For everything else, prefer the increased flexibility of readonly constants.

  • 相关阅读:
    11.4 iftop:动态显示网络接口流量信息
    10.2-3 ifup&ifdown:激活与禁用网络接口
    10.1 ifconfig:配置或显示网络接口信息
    10.16-17 mailq&mail:显示邮件传输队列&发送邮件
    10.13 nc:多功能网络工具
    Matplotlib_常用图表
    urlrrtrieve()实例_下载微博短视频
    ulrlib案例-爬取百度贴吧
    Scrapy-Spider
    Scrapy-架构
  • 原文地址:https://www.cnblogs.com/taoeternal/p/681726.html
Copyright © 2011-2022 走看看