我们都知道,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)
    ;

    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)
        );
            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)
        ;
    }
}
  • 使用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);  
  }  
  }

const和readonly差别的更多相关文章

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

    总结const. readonly. static三者区别: (有人问我,看似简单,我也没能立刻回答出来,总结一下,分享一下.) const:静态常量,也称编译时常量(compile-time con ...

  2. 总结const、readonly、static三者的区别

    const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编译时常量的原因是它编译时会将其替换为所对应的值: b.静态 ...

  3. 转:总结const、readonly、static三者的区别

    const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编译时常量的原因是它编译时会将其替换为所对应的值: b.静态 ...

  4. 基础知识---const、readonly、static

    const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编译时常量的原因是它编译时会将其替换为所对应的值: b.静态 ...

  5. 总结const、readonly、static三者的区别【收藏、转载】20190614

    总结const.readonly.static三者的区别 const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编 ...

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

    前言 不知道大家对const和readonly关键字两者的区别了解多少,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态常量和动态常量. 静态常量 所谓静态常量就是在编译期间会对变量 ...

  7. const 与 readonly知多少

    原文地址: http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html 尽管你写了很多年的C#的代码,但是可能当别人问到你cons ...

  8. [c#基础]关于const和readonly常见的笔试题剖析

    引言 有那么几天没更新博客了,发现到了不得不写的地步,总是有那么个声音在强迫自己,虽然工作很累,但是有些东西不写出来,不能原谅自己.今天为什么总结这两个关键字的区别,总觉得这两个关键字的用法用的太习惯 ...

  9. const 和 readonly

    const 和 readonly 的异同 Const readonly 字面意 不变常量,不可修改 只读操作,不可写 初始化 必须在声明的同时赋值 可在声明和构造方法中进行赋值 所属关系 类.即sta ...

随机推荐

  1. Lambda表达式 =>(msdn)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. Angularjs中input的指令和属性

    建议添加 novalidate属性(可无值)到form标签上,这样可以保证在表单不合法的情况下阻止浏览器继续提交数据. 可以给表单元素 input 添加 required 属性(可无值),让该表单成为 ...

  3. Hadoop集群安装配置教程_Hadoop2.6.0_Ubuntu/CentOS

    摘自:http://www.powerxing.com/install-hadoop-cluster/ 本教程讲述如何配置 Hadoop 集群,默认读者已经掌握了 Hadoop 的单机伪分布式配置,否 ...

  4. 斜率优化dp(POJ1180 Uva1451)

    学这个斜率优化dp却找到这个真心容易出错的题目,其中要从n倒过来到1的确实没有想到,另外斜率优化dp的算法一开始看网上各种大牛博客自以为懂了,最后才发现是错了. 不过觉得看那些博客中都是用文字来描述, ...

  5. poj2001 Shortest Prefixes (trie)

    读入建立一棵字母树,并且每到一个节点就增加这个节点的覆盖数. 然后再重新扫一遍,一旦碰到某个覆盖数为1就是这个单词的最短前缀了. 不知为何下面的程序一直有bug……不知是读入的问题? type nod ...

  6. POJ 2391 Ombrophobic Bovines ★(Floyd+二分+拆点+最大流)

    [题意]有n块草地,一些奶牛在草地上吃草,草地间有m条路,一些草地上有避雨点,每个避雨点能容纳的奶牛是有限的,给出通过每条路的时间,问最少需要多少时间能让所有奶牛进入一个避雨点. 和POJ2112很类 ...

  7. 【原创】 Shuffling

    在机器学习领域中,经常会听到“shuffling"这个术语.那么,shuffling到底是什么意思呢. 通常,shuffling指的是在SGD怎样依赖训练数据输入顺序的算法中,将训练数据随机 ...

  8. RMAN数据库异机迁移

    本文讲述如何用rman将一个库迁移到另一个服务器上. 服务器A:linux es4 + oracle9204 (源)服务器B:linux es4 + oracle9204 (目标) 一.创建目录 为了 ...

  9. ViewPager 滑动页(二)

    需求:滑动展示页,能够使用本地数据,及获取服务器数据进行刷新操作,并实现页面自动切换: 效果图: 实现分析: 1.目录结构: 代码实现: 1.PosterView.java package com.j ...

  10. log4j和web.xml配置webAppRootKey 的问题

    在tomcat下部署两个或多个项目时,web.xml文件中最好定义webAppRootKey参数,如果不定义,将会缺省为“webapp.root”,如下: <!-- 应用路径 --> &l ...