閱讀153 返回首頁    go 技術社區[雲棲]


readonly和const

 

   const應該稱為常量

   readonly則應稱為隻讀變量

  

   const可用於修飾class的field或者一個局部變量(local variable);

   readonly僅僅用於修飾class的field。

 

  const常量的值必定在編譯時就已明確並且恒定的

  readonly常量卻有一點不同,那就是其值可以在運行時編譯。當然它也必須遵守作為常量的約束,那就是值

  必須恒定不變。

 

  const常量必須在聲明的同時對其進行賦值,並且確保該值在編譯時可確定並恒定

  readonly常量則可以根據情況,有兩種賦值方式

  a 聲明的同時對其賦予一個編譯時確定並恒定的值,或者將其值的初始化工作

  b 交給實例構造函數(instant constructor)完成。

  如public readonly string m_Now = DateTime.Now.ToString();,m_Now會隨著運行時實際情況變化而化。

 

const常量屬於類級別(class level)而不是實例對象級別(instant object level),並且它不能跟static結合一起使用,該常量的值將由整個類的所有實例對象共同分享。

 

readonly常量既可以是類級別也可以是實例對象級別的,這取決於它的聲明以及初始化工作怎麼實施。readonly可以與static結合使用,用於指定該常量屬於類級別,並且把初始化工作交由靜態構造函數(static constructor)完成。

 

能被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;

 

 

namespace ConstantLab

{

    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;

    }

 

    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();

        }

    }

}

 

使用Visual C#在Main()裏麵使用IntelliSence插入Constant的相關field的時候,發現

①ReadonlyInt和InstantReadonlyInt需要指定Constant的實例對象(二者都是readonly)

②ConstInt和StaticReadonlyInt卻要指定Constant class。  (一個是const,另一個是static readonly)

 

可見

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兩者所修飾的量都說成“常量”,希望沒有引起誤會。

 

 

原帖地址:https://blog.csdn.net/powerglover/archive/2009/07/15/4350247.aspx

最後更新:2017-04-02 22:16:00

  上一篇:go 為什麼要override ToString()方法——讀《你必須知道的.net》
  下一篇:go C#中string的幾種轉換方法的異同——《讀你必須知道的.net》