const和readonly差别

我们都知道,const和static readonly的确非常像:通过类名而不是对象名进行訪问,在程序中仅仅读等等。在多数情况下能够混用。二者本质的差别在于,const的值是在编译期间确定的,因此仅仅能在声明时通过常量表达式指定其值。而static readonly是在执行时计算出其值的,所以还能够通过静态构造函数来赋值。明确了这个本质差别,我们就不难看出以下的语句中static readonly和const是否能互换了:

1. static readonly MyClass myins = new MyClass();
2. static readonly MyClass myins = null;
3. static readonly B = 10;   static readonly A = B * 20;
4. static readonly int [] constIntArray = new int[] {1, 2, 3};
5. void SomeFunction()
   {
      const int a = 10;
      ...
   }
6.private static string astr="abcd";
  private const string str = astr+"efg";
1:不能够换成const。new操作符是须要运行构造函数的,所以无法在编译期间确定
2:能够换成const。我们也看到,Reference类型的常量(除了String)仅仅能是Null。
3:能够换成const。我们能够在编译期间非常明白的说,A等于200。
4:不能够换成const。道理和1是一样的,尽管看起来1,2,3的数组的确就是一个常量。
5:不能够换成readonly,readonly仅仅能用来修饰类的field,不能修饰局部变量,也不能修饰property等其它类成员。

6.错误:假设在astr前加上const或者const改为readonly就可以;

总结:1.const、readonly和static readonly定义的常量,指定初始值后(包含在构造函数内指定的初始值) 将不可更改,可读不可写;
        2.const定义时必须指定初始值,而readonly定义时能够不进行初始化(MS建议在定义时初始值),同一时候也能够在构造函数内指定初始值,

并以构造函数内指定的值为准;

3.const和static readonly定义的常量是静态的,仅仅能由类直接訪问;而readonly定义的常量是非静态 的,仅仅能由实例对象訪问;  
        4.static readonly常量,假设在构造函数内指定初始值,则必须是静态无參构造函数;
        5.const是编译时常量,readonly是执行时常量;cosnt较高效,readonly较灵活。在应用上以static readonly取代const,以平衡const在灵活性上的不足,
           同一时候克服编译器优化cosnt性能,所带来的程序集引用不一致问题;

文章2:

readonly和const比較

前天犯了个低级错误,是关于readonly的,总结了一下:   
C#的readonlykeyword仅仅能在字段上面使用
public readonly TcpClient client;
不能在类,方法,属性上面使用readonly!!
顺便看了一下readonly和const的差别:

  • readonly和const都是用来标识常量的。
  • const可用于修饰class的field或者一个局部变量(local variable);而readonly只用于修饰class的field。
  • const常量的值必然在编译时就已明白而且恒定的;而readonly常量却有一点不同,那就是其值能够在执行时编译,当然,它也必须遵守作为常量的约束,那就是值必须恒定不变。
  • const常量必须在声明的同一时候对其进行赋值,而且确保该值在编译时可确定并恒定;而readonly常量则能够依据情况选择在声明的同一时候对其赋予一个编译时确定并恒定的值,或者将其值的初始化工作交给实例构造函数(instant constructor)完毕。如:public readonly string m_Now = DateTime.Now.ToString();,m_Now会随着执行时实际情况变化而变化。
  • const常量属于类级别(class level)而不是实例对象级别(instant object level),而且它不能跟static结合一起使用,该常量的值将由整个类的全部实例对象共同分享(具体论述參见后面的Remark区域)。
  • readonly常量既能够是类级别也能够是实例对象级别的,这取决于它的声明以及初始化工作怎么实施。readonly能够与static结合使用,用于指定该常量属于类级别,而且把初始化工作交由静态构造函数(static constructor)完毕(有关怎样把readonly常量声明为类级别或实例对象级别的论述清參见后面的Remark区域) 。
  • 能被const修饰声明为常量的类型必须是下面的基元类型(primitive type):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, float, bool, decimal, string。
  • object, 数组(Array)和结构(struct)不能被声明为const常量。
  • 普通情况下,引用类型是不能被声明为const常量的,只是有一个例外:string。该引用类型const常量的值能够有两种情况,string或null。事实上,string尽管是引用类型,可是.NET却对它特别处理,这样的处理叫做字符串恒定性(immutable),使得string的值具有仅仅读特性。有关字符串恒定性的内容,能够參考《Microsoft .NET框架程序设计(修订版)》

Examples:

using System;

public class Order
{
    public Order()
    {
        Guid guid = Guid.NewGuid();
        ID = guid.ToString("D");
    }

    // 对于每一份订单,其订单序号都是实时确定的常量。
    public readonly string ID;

    public override string ToString()
    {
        return "Order ID: " + ID;
    }
}

Explaintion:

  • 假设结合数据库使用,ID field通常都会都会与某个表的主健(primary key)关联起来,如Orders表的OrderID。
  • 数据库的主健通常採用下面三种方式:
    • 自己主动递增值。你能够通过把DataColumn.AutoIncrement设定为true值来激活自己主动递增特性。
    • 唯一名称。这个是使用自定义的算法来生成一个唯一序列号。
    • GUID(全局唯一标识符)。你能够通过System.Guid结构来生成GUID,如上例。

using System;

class Customer
{
    public Customer(string name, int kind)
    {
        m_Name = name;
        m_Kind = kind;
    }

    public const int NORMAL = 0;
    public const int VIP = 1;
    public const int SUPER_VIP = 2;

    private string m_Name;
    public string Name
    {
        get { return m_Name; }
    }

    private readonly int m_Kind;
    public int Kind
    {
        get { return m_Kind; }
    }

    public override string ToString()
    {
        if(m_Kind == SUPER_VIP)
            return "Name: " + m_Name + "[SuperVip]";
        else if(m_Kind == VIP)
            return "Name: " + m_Name + "[Vip]";
        else
            return "Name: " + m_Name + "[Normal]";
    }
}

Remarks:

  • 普通情况下,假设你须要声明的常量是普遍公认的并作为单个使用,比如圆周率,黄金切割比例等。你能够考虑使用const常量,如:public const double PI = 3.1415926;。假设你须要声明常量,只是这个常量会随着实际的执行情况而决定,那么,readonly常量将会是一个不错的选择,比如上面第一个样例的订单号Order.ID。
  • 另外,假设要表示对象内部的默认值的话,而这类值一般是常量性质的,那么也能够考虑const。很多其它时候我们对源码进行重构时(使用Replace Magic Number with Symbolic Constant),要去除魔数(Magic Number)的影响都会借助于const的这样的特性。
  • 对于readonly和const所修饰的变量到底是属于类级别的还是实例对象级别的问题,我们先看看例如以下代码:

Using directives#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace ConstantLab
{
    class Program
    {
        static void Main(string[] args)
        {
            Constant c = new Constant(3);
            Console.WriteLine("ConstInt = " + Constant.ConstInt.ToString());
            Console.WriteLine("ReadonlyInt = " + c.ReadonlyInt.ToString());
            Console.WriteLine("InstantReadonlyInt = " + c.InstantReadonlyInt.ToString());
            Console.WriteLine("StaticReadonlyInt = " + Constant.StaticReadonlyInt.ToString());

            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
        }
    }

    class Constant
    {
        public Constant(int instantReadonlyInt)
        {
            InstantReadonlyInt = instantReadonlyInt;
        }

        public const int ConstInt = 0;

        public readonly int ReadonlyInt = 1;

        public readonly int InstantReadonlyInt;

        public static readonly int StaticReadonlyInt = 4;
    }
}

  • 使用Visual C#在Main()里面使用IntelliSence插入Constant的相关field的时候,发现ReadonlyInt和InstantReadonlyInt须要指定Constant的实例对象;而ConstInt和StaticReadonlyInt却要指定Constant class(參见上面代码)。可见,用const或者static readonly修饰的常量是属于类级别的;而readonly修饰的,不管是直接通过赋值来初始化或者在实例构造函数里初始化,都属于实例对象级别。
  • 普通情况下,假设你须要表达一组相关的编译时确定常量,你能够考虑使用枚举类型(enum),而不是把多个const常量直接嵌入到class中作为field,只是这两种方式没有绝对的孰优孰劣之分。

using System;

enum CustomerKind
{
    SuperVip,
    Vip,
    Normal
}

class Customer
{
    public Customer(string name, CustomerKind kind)
    {
        m_Name = name;
        m_Kind = kind;
    }

    private string m_Name;
    public string Name
    {
        get { return m_Name; }
    }

    private CustomerKind m_Kind;
    public CustomerKind Kind
    {
        get { return m_Kind; }
    }

    public override string ToString()
    {
        return "Name: " + m_Name + "[" + m_Kind.ToString() + "]";
    }
}

  • 然而,当这样的结合使用枚举和条件推断的代码阻碍了你进行更灵活的扩展,并有可能导致日后的维护成本添加,你能够代之以多态,使用Replace Conditional with Polymorphism来对代码进行重构。(有关多态的具体介绍,请參见《今天你多态了吗?》一文。)

Comments:

  • readonly field准确来说应该翻译成为“仅仅读域”,这里是为了统一翻译用语才将它和const两者所修饰的量都说成“常量”,希望没有引起误会。

===============================================================================

有时你不想在在程序执行时改变域,如执行时程序依靠的数据文件,一个math类的pi值,或者不论什么在程序执行时你不想改变的值。为了处理这种情况,c#中定义了两个近似的、相关的成员类型:contants和read-only域。  
   
  Constants域  
   
  从字面能够看出,常数(用keywordconst表示)在应用程序执行期间保持不变。当定义某个事物为const时记住两个规则:第一,定义成常数的成员的值是在编译时设置的——或者是由编程者指定,或者是由编译器设置缺省值;第二,一个常数成员的值必须被写为一个字面常数。  
  为了定义一个常数域,在要定义的成员前使用一个constkeyword,例如以下所看到的:  
   
  using   System;  
   
  class   MagicNumbers  
  {  
  public   const   double   pi   =   3.1415;  
  public   const   int   answerToAllLifesQuestions   =   42;  
  }  
   
  class   ConstApp  
  {  
  public   static   void   Main()  
  {  
  Console.WriteLine("pi   =   {0},   everything   else   =   {1}",  
  MagicNumbers.pi,   MagicNumbers.answerToAllLifesQuestions);  
  }  
  }  
   
  请注意这个代码的一个关键点——不必在client实例化MagicNumbers类,由于const成员缺省是静态的。为了更清楚的展示它,我们列出这两个域在MSIL中生成时的情况:  
   
  answerToAllLifesQuestions   :   public   static   literal   int32   =   int32(0x0000002A)  
  pi   :   public   static   literal   float64   =   float64(3.1415000000000002)  
   
  Read-only   域  
   
  使用const域是很实用的,由于他清楚的表明了编程者的意图。然而,这仅仅能用于在编译时已经知道值的情况下。所以,当一个域仅仅有在执行时才干知道值并且一旦初始化以后值便不能改变的情况下,编程者该怎么办呢?C#语言的设计者用Read-only域的办法攻克了这个问题(在其它语言中一般不会处理)。  
  当你用readonlykeyword定义了一个域时,你仅仅能在一个地方设置这个域的值——构造函数。以后,域的值便不能被自身类或者使用这个类的客户改变。让我们看一个图形应用程序记录屏幕分辨率的样例。你不能用const处理这个问题,由于应用程序直到执行时才干确定终端用户的屏幕分辨率,所以你必须使用这种代码:  
   
  using   System;  
   
  class   GraphicsPackage  
  {  
  public   readonly   int   ScreenWidth;  
  public   readonly   int   ScreenHeight;  
   
  public   GraphicsPackage()  
  {  
  this.ScreenWidth   =   1024;  
  this.ScreenHeight   =   768;  
  }  
  }  
   
  class   ReadOnlyApp  
  {  
  public   static   void   Main()  
  {  
  GraphicsPackage   graphics   =   new   GraphicsPackage();  
  Console.WriteLine("Width   =   {0},   Height   =   {1}",  
  graphics.ScreenWidth,    
  graphics.ScreenHeight);  
  }  
  }  
   
  猛一看,这个代码正是我们须要的。然而,另一点小问题:我们定义的readonly域是一个实例域,这意味着是用户在使用域之前必须先实例化类。这可能也不是什么问题,甚至这正是你想做的——在实例化类的时候正能够初始化readonly域的值。但假设你想要一个被定义成静态的、能在执行时被初始化的常数时该怎么办呢?这时,我们能够定义一个带static和readonly修饰符的域。然后,创建一个构造函数的特殊类型——static   constructor。静态函数能够用来初始化static域、readonly域或其它的域。如今我们改变先前的样例,给屏幕分辨率域加上static和readonly,并且添加一个静态构造函数。  
   
  using   System;  
   
  class   GraphicsPackage  
  {  
  public   static   readonly   int   ScreenWidth;  
  public   static   readonly   int   ScreenHeight;  
   
  static   GraphicsPackage()  
  {  
  //   Code   would   be   here   to    
  //   calculate   resolution.  
  ScreenWidth   =   1024;  
  ScreenHeight   =   768;  
  }  
  }  
   
  class   ReadOnlyApp  
  {  
  public   static   void   Main()  
  {  
  Console.WriteLine("Width   =   {0},   Height   =   {1}",    
  GraphicsPackage.ScreenWidth,    
  GraphicsPackage.ScreenHeight);  
  }  
  }

时间: 2024-11-14 06:23:45

const和readonly差别的相关文章

C# 总结const、 readonly、 static三者区别:

总结const. readonly. static三者区别: (有人问我,看似简单,我也没能立刻回答出来,总结一下,分享一下.) const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编译时常量的原因是它编译时会将其替换为所对应的值: b.静态常量在速度上会稍稍快一些,但是灵活性却比动态常量差一些: c.静态常量,隐式是静态的,即被static隐式修饰过,不能再用static重复修饰, d.在声明时初始化: e

[c#] const 与 readonly

c# 中 const 与 readonly 关键字看似相同,实则不同.重点在于确定值的时间. const const 很简单,就是一个常量,不可以被 static 修饰,因为被 const 修饰的字段自动成为静态字段,其值是在编译时可以确定的. readonly readonly 可以修饰实例字段(不被 static 修饰的字段),也可以修饰静态字段(被 static 修饰的字段).意指为"只读".其值确定的时间在类的构造函数中. 总结 关键字 确定值的时机 const 编译时 rea

const和readonly

const:常量,编译时即需要确定值 readonly:只读变量,运行时确定值 1 class ConstReadonlyTest 2 { 3 //const String str;//错误:常量字段定义时需要指定初始值 4 //const Object obj = new Object();//错误:常量字段不能使用new初始化,表达式必须是常量(字符串可以) 5 //const Object obj = new StructTest();//错误:表达式必须是常量不能使用new初始化(即使是

const,readonly,static

1.const 表示的是常量(constant),始终不会发生改变,在编译时就确定了.所以类中定义一个常量可以被类访问也可以被类的实例访问.定义时就不能和static一起用.如果用了也是没有作用的,所以语法就规定其是无效的.在声明时同时初期化. private const string Name="abc"; 2.readonly 值在运行期决定,有一次确定其值的机会.其是可以被类访问还是类的实例访问,就看static.可以和static一起使用,这与一般数据成员一样.可以在两类地方赋

C#庖丁解牛之const与readonly

一.const与readonly的争议 你一定写过const,也一定用过readonly,但说起两者的区别,并说出何时用const,何时用readonly,你是否能清晰有条理地说出个一二三? const与readonly之所以有如此争议,是因为彼此都存在"不可改变"这一特性,对于二者而言,我们需要关心的是,什么时候开始不可变?什么是不可改变的?这就引出了我们下面要讨论的话题. 二.什么时候开始不可变? 我们先抛出结论. const在程序运行的任何时候都是不可变的,无论什么时候开始,什么

C#基础知识七之const和readonly关键字

前言 不知道大家对const和readonly关键字两者的区别了解多少,之前真不是很清楚,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态变量和动态变量. 静态变量 所谓静态变量就是在编译期间会对变量进行解析,再讲常量的值替换成初始化的值.定义时必须初始化. 动态变量 所谓动态变量就是编译期间会将变量标示只读常量,而不用常量的值代替,定义时可以不初始化,可以延迟到构造函数. const和readonly

const与readonly常量

const与readonly都是用来定义常量,但是它们有什么区别呢? 下面我们来简要的说明一下: const修饰的常量是编译时常量,如:public const String PI=3.1415;什么是编译时常量,通俗来讲就是指你在声明时,必须要进行赋值(也就是初始化),如果不赋值,编译时会出现说“常量字段要求提供一个值”的异常. readonly修饰的是运行时常量,可以在声明中赋值,也可以在构造函数中赋值(注意只能在这两个地方赋值). http://www.cnblogs.com/royenh

.net 中const 与readonly的区别???

const和readonly都是只读的.但是const修饰的变量必须在声明时赋值.readonly修饰的变量可以在声明时或者构造函数里赋值.private const double pi=3.14;class A { private readonly int a; public A(int v) { a=v; } }

const和readonly你真的懂吗?

第二遍文章我打算把const和readonly的区别拿出来讲下,因为写代码这么久我都还没搞清楚这两者的区别,实在有点惭愧,所以这一次我打算搞清楚它. 定义 来看看MSDN的解释: readonly:readonly关键字是可以在字段上使用的修饰符.当字段声明包括readonly修饰符时,该声明引入的字段赋值只能作为声明的一部分,或者出现在同一类的构造函数中. const:使用 const 关键字来声明某个常量字段或常量局部变量. 常量字段和常量局部变量不是变量并且不能修改. 太多理论的讲解有些人