ความแตกต่างระหว่าง const และแบบอ่านอย่างเดียวใน C # คืออะไร


1362

ความแตกต่างระหว่างconstและreadonlyใน C # คืออะไร?

เมื่อไหร่ที่คุณจะใช้อันอื่น


ฉันต้องดูคำตอบหลาย ๆ คำเพื่อหาลิงค์นี้ แต่มันก็ดี Eric Lippert ใช้ความไม่สามารถเปลี่ยนแปลงได้ใน C #
Frank Bryce

2
@donstack จริงตามที่อ้างอิง C # , เขตข้อมูลที่อ่านได้อย่างเดียวจะได้รับมอบหมายและพระราชเสาวนีย์หลายครั้งภายในการประกาศภาคสนามและคอนสตรัค
Marques

คำตอบ:


1289

นอกเหนือจากความแตกต่างที่ชัดเจนของ

  • ต้องประกาศค่าในเวลาที่คำจำกัดความสำหรับค่าconstVS readonlyสามารถคำนวณแบบไดนามิก แต่ต้องได้รับการกำหนดก่อนที่นวกรรมิกจะออก .. หลังจากนั้นมันจะถูกแช่แข็ง
  • '' s const staticเป็นโดยปริยาย คุณใช้ClassName.ConstantNameสัญลักษณ์เพื่อเข้าถึงพวกเขา

มีความแตกต่างที่ลึกซึ้ง AssemblyAพิจารณาระดับที่กำหนดไว้ใน

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyBการอ้างอิงAssemblyAและใช้ค่าเหล่านี้ในรหัส เมื่อสิ่งนี้รวบรวม

  • ในกรณีของconstค่ามันก็เหมือนการค้นหาแทนที่ค่า 2 คือ 'อบเข้าสู่' AssemblyBIL ซึ่งหมายความว่าหากในวันพรุ่งนี้ฉันจะอัปเดตI_CONST_VALUEเป็น 20 ในอนาคต AssemblyBยังคงมี 2 จนฉัน recompile มัน
  • ในกรณีของreadonlyค่ามันเป็นเหมือนrefที่ตั้งหน่วยความจำ ค่าไม่ได้ถูกอบเข้าสู่AssemblyBIL ซึ่งหมายความว่าหากตำแหน่งหน่วยความจำถูกอัพเดตให้AssemblyBรับค่าใหม่โดยไม่ต้องคอมไพล์ใหม่ ดังนั้นหากI_RO_VALUEอัปเดตเป็น 30 คุณจะต้องสร้างAssemblyAเท่านั้น ลูกค้าทั้งหมดไม่จำเป็นต้องทำการคอมไพล์ใหม่

constดังนั้นถ้าคุณมีความมั่นใจว่าค่าคงที่จะไม่เปลี่ยนการใช้งาน

public const int CM_IN_A_METER = 100;

แต่ถ้าคุณมีอย่างต่อเนื่องที่อาจมีการเปลี่ยนแปลง (egwrt แม่นยำ) .. readonlyหรือเมื่อมีข้อสงสัยการใช้งาน

public readonly float PI = 3.14;

อัปเดต: Aku ต้องได้รับการกล่าวถึงเพราะเขาชี้ให้เห็นสิ่งนี้ก่อน นอกจากนี้ฉันต้องเสียบที่ฉันเรียนรู้สิ่งนี้ .. มีประสิทธิภาพ C # - Bill Wagner


77
staticจุดน่าจะเป็นจุดที่สำคัญที่สุดและมีประโยชน์ -consts are implicitly static
LCJ

28
ส่วนเกี่ยวกับค่าอ้างอิงเป็นสิ่งสำคัญที่สุด ค่า Const สามารถปรับให้เหมาะสม
CodingBarfield

22
readonlyตัวแปรสามารถเปลี่ยนแปลงได้นอกตัวสร้าง (การสะท้อน) มันเป็นเพียงคอมไพเลอร์ที่พยายามขัดขวางคุณจากการแก้ไข var นอกนวกรรมิก
Bitterblue

12
readonlyไม่อนุญาตให้เปลี่ยนตัวแปร@ mini-me เมื่อตัวสร้างสร้างเสร็จแม้ผ่านการสะท้อนกลับ รันไทม์เกิดขึ้นเพื่อไม่บังคับใช้ รันไทม์ยังเกิดขึ้นไม่ได้ในการบังคับใช้ที่คุณไม่ได้เปลี่ยนstring.Emptyไป"Hello, world!"แต่ฉันยังคงจะไม่เรียกร้องที่ว่านี้ทำให้string.Emptyสามารถปรับเปลี่ยนหรือรหัสที่ไม่ควรคิดว่าstring.Emptyจะเป็นสตริงความยาวเป็นศูนย์

7
blogs.msmvps.com/jonskeet/2014/07/16/…เป็นสิ่งที่น่าสนใจในการอ่านค่าใช้จ่ายแบบอ่านอย่างเดียว
CAD bloke

275

มี gotcha พร้อม consts! หากคุณอ้างอิงค่าคงที่จากชุดประกอบอื่นค่าของมันจะถูกรวบรวมไว้ในชุดสายเรียก ด้วยวิธีนี้เมื่อคุณอัปเดตค่าคงที่ในแอสเซมบลีอ้างอิงมันจะไม่เปลี่ยนแปลงในแอสเซมบลีการเรียก!


8
ในการแยกส่วน (Reflector, ILSpy, .. ) ค่าคงที่ไม่เคยถูกอ้างอิงโดยบุคคลใด ๆ ไม่ว่าจะมีชุดประกอบเดียวกันหรือชุดประกอบอื่นดังนั้นคุณจึงไม่สามารถวิเคราะห์การใช้ค่าคงที่ในรหัสที่คอมไพล์ได้เลย
springy76

159

ค่าคงที่

  • ค่าคงที่เป็นค่าคงที่โดยค่าเริ่มต้น
  • พวกเขาจะต้องมีค่าในเวลารวบรวม (คุณสามารถมีเช่น 3.14 * 2 แต่ไม่สามารถเรียกวิธีการ)
  • สามารถประกาศได้ภายในฟังก์ชั่น
  • จะถูกคัดลอกลงในทุกชุดประกอบที่ใช้พวกเขา (ทุกชุดประกอบได้รับสำเนาของค่าในเครื่อง)
  • สามารถใช้ในคุณลักษณะ

ฟิลด์อินสแตนซ์แบบอ่านอย่างเดียว

  • ต้องมีการตั้งค่าตามตัวสร้างเวลาออก
  • ได้รับการประเมินเมื่อสร้างอินสแตนซ์

ฟิลด์แบบอ่านอย่างเดียวแบบคงที่

  • ได้รับการประเมินเมื่อมีการเรียกใช้การประมวลผลรหัสอ้างอิงคลาส (เมื่อมีการสร้างอินสแตนซ์ใหม่หรือใช้วิธีการคงที่)
  • ต้องมีค่าที่ประเมินตามเวลาที่ตัวสร้างสแตติกเสร็จสิ้น
  • ไม่แนะนำให้ใส่ ThreadStaticAttribute บนสิ่งเหล่านี้ (ตัวสร้างแบบสแตติกจะถูกเรียกใช้งานในหนึ่งเธรดเท่านั้นและจะตั้งค่าสำหรับเธรดของตนเธรดอื่น ๆ ทั้งหมดจะมีค่านี้ไม่กำหนดค่าเริ่มต้น)

58

เพียงเพื่อเพิ่ม ReadOnly สำหรับประเภทการอ้างอิงเท่านั้นทำให้การอ้างอิงไม่ใช่ค่าแบบอ่านอย่างเดียว ตัวอย่างเช่น:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

มีประเภทอ้างอิงอื่นนอกเหนือจากstringที่คุณสามารถใช้เป็นค่าคงที่ได้หรือไม่?
springy76

คุณสามารถมีconstประเภทการอ้างอิงอื่นที่ไม่ใช่สตริง แต่ค่าคงที่สามารถมีค่าnullได้เท่านั้น
Mike Rosoft

40

นี้จะอธิบายมัน สรุป: const จะต้องเริ่มต้นในเวลาที่ประกาศสามารถอ่านได้อย่างเดียวบนตัวสร้าง (และมีค่าที่แตกต่างกันขึ้นอยู่กับตัวสร้างที่ใช้)

แก้ไข: ดู gotcha ของ Gishu ด้านบนสำหรับความแตกต่างที่ลึกซึ้ง


32

const: ไม่สามารถเปลี่ยนแปลงได้ทุกที่

readonly: ค่านี้สามารถเปลี่ยนแปลงได้ในตัวสร้างเท่านั้น ไม่สามารถเปลี่ยนแปลงได้ในฟังก์ชั่นปกติ


26

มี gotcha ขนาดเล็กพร้อมอ่านอย่างเดียว สามารถตั้งค่าฟิลด์แบบอ่านอย่างเดียวได้หลายครั้งภายในตัวสร้าง แม้ว่าค่าจะถูกตั้งค่าในตัวสร้างการโยงโซ่ที่แตกต่างกันสองตัวมันยังคงได้รับอนุญาต


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}

26

สมาชิกคงที่จะถูกกำหนดในเวลารวบรวมและไม่สามารถเปลี่ยนแปลงได้ในขณะทำงาน ค่าคงที่จะประกาศเป็นฟิลด์โดยใช้constคำหลักและต้องเริ่มต้นตามที่ประกาศไว้

public class MyClass
{
    public const double PI1 = 3.14159;
}

readonlyสมาชิกเป็นเหมือนอย่างต่อเนื่องในการที่จะแสดงให้เห็นถึงความคุ้มค่าที่ไม่มีการเปลี่ยนแปลง ความแตกต่างคือreadonlyสมาชิกสามารถเริ่มต้นได้ที่รันไทม์ในตัวสร้างเช่นเดียวกับความสามารถในการเริ่มต้นตามที่พวกเขาจะประกาศ

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

const

  • พวกเขาไม่สามารถประกาศเป็น static (พวกเขาจะคงที่โดยปริยาย)
  • ค่าของค่าคงที่จะถูกประเมิน ณ เวลารวบรวม
  • ค่าคงที่จะเริ่มต้นได้ที่การประกาศเท่านั้น

อ่านเท่านั้น

  • พวกเขาสามารถเป็นอินสแตนซ์ระดับหรือคงที่
  • มีการประเมินค่าในขณะดำเนินการ
  • แบบอ่านอย่างเดียวสามารถเริ่มต้นได้ในการประกาศหรือโดยรหัสในตัวสร้าง

6
พวกเขาไม่สามารถคงที่พวกเขาจะคงที่ คุณควรทำให้ชัดเจนถ้าคุณหมายถึงคนที่ไม่สามารถประกาศได้static const int i = 0;
nawfal

คุณช่วยอธิบายได้ไหมว่าทำไมconstการประกาศไม่สามารถทำได้ภายในวิธี
Minh Tran

21

const เป็นค่าคงที่เวลาคอมไพล์ในขณะที่อนุญาตให้คำนวณค่าแบบอ่านได้ในเวลารันไทม์และตั้งค่าในตัวสร้างหรือตัวกำหนดค่าเริ่มต้นของฟิลด์ ดังนั้น 'const' จึงเป็นค่าคงที่เสมอ แต่ 'readonly' จะเป็นแบบอ่านอย่างเดียวเมื่อถูกกำหนด

Eric Lippertจากทีม C # มีข้อมูลเพิ่มเติมเกี่ยวกับประเภทที่ไม่สามารถเปลี่ยนแปลงได้


15

นี่คือลิงค์อื่นที่แสดงว่า const ไม่ปลอดภัยหรือเกี่ยวข้องกับประเภทการอ้างอิง

สรุป :

  • ค่าของคุณสมบัติ const ของคุณถูกกำหนด ณ เวลารวบรวมและไม่สามารถเปลี่ยนแปลงได้ในขณะทำงาน
  • Const ไม่สามารถทำเครื่องหมายเป็นแบบคงที่ได้ - คำหลักจะระบุว่าเป็นแบบคงที่ซึ่งแตกต่างจากช่องแบบอ่านอย่างเดียวซึ่งสามารถ
  • Const ไม่สามารถเป็นอะไรก็ได้ยกเว้นประเภทของค่า (ดั้งเดิม)
  • คำหลักแบบอ่านอย่างเดียวทำเครื่องหมายฟิลด์ว่าไม่สามารถเปลี่ยนได้ อย่างไรก็ตามคุณสมบัติสามารถเปลี่ยนแปลงได้ภายในตัวสร้างของชั้นเรียน
  • คำหลักที่อ่านได้อย่างเดียวเท่านั้นยังสามารถรวมกับสแตติกเพื่อให้มันทำงานในลักษณะเดียวกับ const (atleast บนพื้นผิว) มีความแตกต่างที่ทำเครื่องหมายไว้เมื่อคุณดู IL ระหว่างทั้งสอง
  • เขตข้อมูล const ถูกทำเครื่องหมายเป็น "ตัวอักษร" ใน IL ในขณะที่อ่านอย่างเดียวคือ "initonly"

11

อ่านอย่างเดียว : ค่าสามารถเปลี่ยนแปลงได้ผ่าน Ctor ตอนรันไทม์ แต่ไม่ผ่านฟังก์ชั่นสมาชิก

คงที่ : โดยดูถูกคงที่ ค่าไม่สามารถเปลี่ยนแปลงได้จากทุกที่ (Ctor, ฟังก์ชั่น, รันไทม์และอื่น ๆ ไม่มีที่)


ขอบคุณสำหรับการไม่ได้ทำให้ฉันอ่าน 4 วรรคเพียงสำหรับทั้งสองสิ่งที่ได้ ...
ดอนชีเดิล

9

อีก gotcha อื่น: ค่าแบบอ่านอย่างเดียวสามารถเปลี่ยนแปลงได้โดยรหัส "devious" ผ่านการสะท้อนกลับ

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

ฉันสามารถเปลี่ยนฟิลด์ที่สืบทอดแบบอ่านอย่างเดียวใน C # โดยใช้การสะท้อนได้หรือไม่?


6

ฉันเชื่อว่าconstค่าเหมือนกันสำหรับวัตถุทั้งหมด (และต้องเริ่มต้นด้วยการแสดงออกตามตัวอักษร) ในขณะที่readonlyสามารถแตกต่างกันสำหรับแต่ละ instantiation ...


5

สมาชิกในทีมหนึ่งคนในสำนักงานของเราได้ให้คำแนะนำต่อไปนี้เกี่ยวกับเวลาที่จะใช้ const, static และ readonly:

  • ใช้constเมื่อคุณมีตัวแปรประเภทที่คุณสามารถรู้ได้ในขณะใช้งานจริง (สตริงตัวอักษร, int, double, enums, ... ) ที่คุณต้องการให้อินสแตนซ์ทั้งหมดหรือผู้บริโภคของคลาสสามารถเข้าถึงได้โดยที่ค่าไม่ควรเปลี่ยนแปลง
  • ใช้แบบคงที่เมื่อคุณมีข้อมูลที่คุณต้องการให้อินสแตนซ์ทั้งหมดหรือผู้บริโภคของคลาสสามารถเข้าถึงที่ซึ่งค่าสามารถเปลี่ยนแปลงได้
  • ใช้สแตติกแบบอ่านอย่างเดียวเมื่อคุณมีตัวแปรประเภทที่คุณไม่สามารถรู้ได้ในขณะรันไทม์ (ออบเจ็กต์) ที่คุณต้องการให้อินสแตนซ์หรือคอนซูมเมอร์ของคลาสทั้งหมดสามารถเข้าถึงได้โดยที่ค่าไม่ควรเปลี่ยนแปลง
  • ใช้แบบอ่านอย่างเดียวเมื่อคุณมีตัวแปรระดับอินสแตนซ์ที่คุณจะรู้เมื่อสร้างวัตถุที่ไม่ควรเปลี่ยนแปลง

หมายเหตุสุดท้ายประการหนึ่ง: ฟิลด์ const เป็นค่าคงที่ แต่ค่าผกผันไม่เป็นความจริง


1
ฉันคิดว่าคุณหมายถึง "สนทนา" ตรงกันข้ามจะเป็น "เขตข้อมูลที่ไม่ใช่ const ไม่คงที่" ซึ่งอาจจะจริงหรือไม่ก็ได้ การสนทนา "ฟิลด์คงที่คือ (เสมอ) const" ไม่เป็นความจริง
Michael Blackburn

5

ทั้งสองเป็นค่าคงที่ แต่ const ยังมีอยู่ในเวลารวบรวม ซึ่งหมายความว่าแง่มุมหนึ่งของความแตกต่างคือคุณสามารถใช้ตัวแปร const เป็นอินพุตให้กับตัวสร้างแอ็ตทริบิวต์ แต่ไม่สามารถใช้ตัวแปรแบบอ่านอย่างเดียว

ตัวอย่าง:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}

5
  • ควรใช้เมื่อใดconstหรือreadonly

    • const

      • ค่าคอมไพล์เวลา : ค่าคงที่สัมบูรณ์ค่าถูกตั้งค่าระหว่างการประกาศอยู่ในโค้ด IL เอง
    • readonly

      • ค่าคงที่รันไทม์ : สามารถตั้งค่าได้ในตัวสร้าง / init ผ่านทางไฟล์ปรับแต่งเช่นApp.configแต่เมื่อเริ่มต้นแล้วจะไม่สามารถเปลี่ยนแปลงได้

4

ตัวแปรที่ทำเครื่องหมาย const นั้นเป็นแมโคร #define ที่พิมพ์ได้ดีกว่าเล็กน้อยในขณะรวบรวมการอ้างอิงตัวแปร const จะถูกแทนที่ด้วยค่าตามตัวอักษรแบบอินไลน์ ดังนั้นเฉพาะประเภทค่าดั้งเดิมบางชนิดเท่านั้นที่สามารถใช้วิธีนี้ได้ ตัวแปรที่ทำเครื่องหมายว่าอ่านได้อย่างเดียวสามารถตั้งค่าในตัวสร้างในเวลาทำงานและมีการบังคับใช้การอ่านอย่างเดียวในระหว่างเวลาทำงานเช่นกัน มีค่าใช้จ่ายประสิทธิภาพเล็กน้อยที่เกี่ยวข้องกับสิ่งนี้ แต่หมายความว่าคุณสามารถใช้แบบอ่านอย่างเดียวกับประเภทใด ๆ (แม้แต่ประเภทอ้างอิง)

นอกจากนี้ตัวแปร const จะเป็นแบบสแตติกโดยกำเนิดในขณะที่ตัวแปรแบบอ่านอย่างเดียวอาจเป็นอินสแตนซ์ที่เฉพาะเจาะจงหากต้องการ


เพิ่มว่า const จะพิมพ์มาโคร #define อย่างยิ่ง มิฉะนั้นเราอาจทำให้ผู้คน C หรือ C ++ แตกตื่น :-)
Jason Baker

4

CONST

  1. คำหลัก const สามารถนำไปใช้กับเขตข้อมูลหรือตัวแปรท้องถิ่น
  2. เราจะต้องกำหนดฟิลด์ const ในเวลาที่ประกาศ
  3. ไม่มีการจัดสรรหน่วยความจำเนื่องจากค่า const ถูกฝังในรหัส IL ของตัวเองหลังจากการรวบรวม มันเหมือนกับการค้นหาสิ่งที่เกิดขึ้นทั้งหมดของตัวแปร const และแทนที่ด้วยค่าของมัน ดังนั้นรหัส IL หลังจากการรวบรวมจะมีค่าตายตัวแทนตัวแปร const
  4. Const ใน C # เป็นค่าเริ่มต้นคงที่
  5. ค่าคงที่สำหรับวัตถุทั้งหมด
  6. มีปัญหาการกำหนดรุ่น dll - ซึ่งหมายความว่าเมื่อใดก็ตามที่เราเปลี่ยนตัวแปร const สาธารณะหรือทรัพย์สิน (ในความเป็นจริงมันไม่ควรจะเปลี่ยนตามหลักวิชา) dll หรือชุดประกอบอื่น ๆ ที่ใช้ตัวแปรนี้จะต้องสร้างขึ้นใหม่
  7. เฉพาะชนิดในตัว C # เท่านั้นที่สามารถประกาศเป็นค่าคงที่
  8. ฟิลด์ Const ไม่สามารถส่งผ่านเป็นพารามิเตอร์ ref หรือ out

อ่านเท่านั้น

  1. คำหลักแบบอ่านอย่างเดียวจะใช้กับฟิลด์ที่ไม่ใช่ตัวแปรในตัวเครื่องเท่านั้น
  2. เราสามารถกำหนดเขตข้อมูลแบบอ่านอย่างเดียวในเวลาที่มีการประกาศหรือในตัวสร้างไม่ใช่ในวิธีอื่นใด
  3. หน่วยความจำแบบไดนามิกที่จัดสรรสำหรับเขตข้อมูลแบบอ่านอย่างเดียวและเราสามารถรับค่าได้ในขณะใช้งาน
  4. อ่านอย่างเดียวเป็นของวัตถุที่สร้างขึ้นเพื่อให้เข้าถึงได้ผ่านอินสแตนซ์ของคลาสเท่านั้น เพื่อให้เป็นสมาชิกของคลาสเราจำเป็นต้องเพิ่มคำหลักคงที่ก่อนที่จะอ่านได้อย่างเดียว
  5. ค่าอาจแตกต่างกันขึ้นอยู่กับคอนสตรัคเตอร์ที่ใช้ (เนื่องจากเป็นของวัตถุของคลาส)
  6. หากคุณประกาศประเภทที่ไม่ใช่ดั้งเดิม (ประเภทการอ้างอิง) เนื่องจากการอ้างอิงแบบอ่านอย่างเดียวเท่านั้นจะไม่เปลี่ยนรูปไม่ใช่วัตถุที่มีอยู่
  7. เนื่องจากได้รับค่า ณ รันไทม์จึงไม่มีปัญหาเกี่ยวกับเวอร์ชัน dll กับฟิลด์ / คุณสมบัติแบบอ่านอย่างเดียว
  8. เราสามารถส่งผ่านฟิลด์แบบอ่านอย่างเดียวเป็นพารามิเตอร์อ้างอิงหรือออกในบริบทตัวสร้าง

3

อีกgotcha

เนื่องจาก const ใช้งานได้กับชนิดข้อมูลพื้นฐานเท่านั้นหากคุณต้องการทำงานกับคลาสคุณอาจรู้สึกว่า "ถูกบังคับ" ให้ใช้ ReadOnly อย่างไรก็ตามระวังกับดัก! อ่านอย่างเดียวหมายความว่าคุณไม่สามารถแทนที่วัตถุด้วยวัตถุอื่นได้ (คุณไม่สามารถอ้างถึงวัตถุอื่นได้) แต่กระบวนการใด ๆ ที่มีการอ้างอิงถึงวัตถุนั้นมีอิสระที่จะแก้ไขค่าภายในวัตถุ!

ดังนั้นอย่าสับสนกับการคิดว่า ReadOnly บอกเป็นนัยว่าผู้ใช้ไม่สามารถเปลี่ยนแปลงสิ่งต่างๆได้ ไม่มีไวยากรณ์ง่าย ๆ ใน C # เพื่อป้องกันการสร้างอินสแตนซ์ของคลาสจากการเปลี่ยนแปลงค่าภายใน (เท่าที่ฉันรู้)


ใช่นั่นเป็นธีมทั่วไปมากกว่า หากคุณมีคุณสมบัติรับเฉพาะการเปิดเผย arraylist คุณยังคงสามารถแก้ไข arraylist ได้ คุณไม่สามารถตั้งค่า arraylist ให้เป็นคุณสมบัตินั้นได้ แต่คุณไม่สามารถหยุดผู้ใช้จากการแก้ไข arraylist
Gishu

3

constจะต้องมีการกำหนดค่าตายตัวที่เป็นreadonlyสามารถตั้งค่าในการสร้างการเรียน


3

มีความแตกต่างที่โดดเด่นระหว่างเขตข้อมูล const และแบบอ่านอย่างเดียวใน C # .Net

const เป็นค่าคงที่เริ่มต้นและจะต้องเริ่มต้นด้วยค่าคงที่ซึ่งไม่สามารถแก้ไขได้ในภายหลัง ไม่อนุญาตให้เปลี่ยนแปลงค่าในตัวสร้างเช่นกัน มันไม่สามารถใช้กับประเภทข้อมูลทั้งหมด สำหรับอดีต DateTime มันไม่สามารถใช้กับประเภทข้อมูล DateTime

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public readonly string Name = string.Empty; //No error, legal

อ่านได้อย่างเดียวสามารถประกาศเป็นแบบคงที่ แต่ไม่จำเป็น ไม่จำเป็นต้องเริ่มต้น ณ เวลาที่ประกาศ ค่าสามารถกำหนดหรือเปลี่ยนแปลงได้โดยใช้ Constructor ดังนั้นจึงให้ประโยชน์เมื่อใช้เป็นสมาชิกคลาสอินสแตนซ์ การสร้างอินสแตนซ์ที่แตกต่างกันสองแบบอาจมีค่าของฟิลด์แบบอ่านอย่างเดียวแตกต่างกัน สำหรับอดีต -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

จากนั้นฟิลด์แบบอ่านอย่างเดียวสามารถเริ่มต้นได้ด้วยค่าเฉพาะทันทีดังนี้:

A objOne = new A(5);
A objTwo = new A(10);

ที่นี่อินสแตนซ์ objOne จะมีค่าของฟิลด์แบบอ่านอย่างเดียวเป็น 5 และ objTwo มี 10 ซึ่งไม่สามารถใช้ const


2

ค่าคงที่จะถูกรวบรวมเป็นคอนซูเมอร์เป็นค่าตัวอักษรในขณะที่สแตติกสตริงจะทำหน้าที่เป็นการอ้างอิงถึงค่าที่กำหนดไว้

ลองทำการสร้างไลบรารี่ภายนอกและใช้มันในแอพพลิเคชั่นคอนโซลจากนั้นเปลี่ยนค่าในไลบรารี่และทำการคอมไพล์ใหม่ (โดยไม่ต้องคอมไพล์โปรแกรมผู้บริโภค) จากนั้นปล่อย DLL ลงในไดเรกทอรีและเรียกใช้ EXE ด้วยตนเอง ที่สตริงคงที่จะไม่เปลี่ยนแปลง


ฉันสงสัยอย่างจริงใจว่าเป็นเรื่องจริง ... ฉันจะไปตรวจสอบ
ljs

นี้เป็นหนึ่งใน 50 วิธีที่เฉพาะเจาะจงในการปรับปรุงของคุณ C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/...
รัสผ่านกล้อง


@ Andrew Hare - ใช่ฉันเพิ่งตรวจสอบ ฉันประหลาดใจมากนั่นคือ gotcha จริงฉันประหลาดใจจริงๆโดยที่ประหลาดใจในกรณีนี้ ... !
ljs

อย่างไรก็ตามฉันคัดค้านการใช้ตัวชี้คำที่นี่ มันไม่ได้เป็นตัวชี้ก็มีการอ้างอิงและมีคือความแตกต่างใน C # เท่าที่คุณสามารถจัดการตัวชี้ไม่มีการจัดการในโหมดที่ไม่ปลอดภัยจึงเป็นสิ่งสำคัญที่จะแยกแยะความแตกต่างระหว่างคนทั้งสอง
ljs

2

คงที่

เราต้องระบุค่าให้กับฟิลด์ const เมื่อมันถูกกำหนด คอมไพเลอร์แล้วบันทึกค่าคงที่ในข้อมูลเมตาของแอสเซมบลี ซึ่งหมายความว่าค่าคงที่สามารถกำหนดได้เฉพาะสำหรับชนิดดั้งเดิมเช่นบูลีน, ถ่าน, ไบต์และอื่น ๆ ค่าคงที่ถือว่าเป็นสมาชิกแบบสแตติกเสมอไม่ใช่สมาชิกอินสแตนซ์

อ่านเท่านั้น

ฟิลด์แบบอ่านอย่างเดียวสามารถแก้ไขได้ที่รันไทม์ นั่นหมายความว่าเราสามารถกำหนดค่าสำหรับค่าโดยใช้ตัวสร้างสำหรับประเภทที่มีการประกาศเขตข้อมูล การตรวจสอบจะกระทำโดยคอมไพเลอร์ที่เขตข้อมูลแบบอ่านอย่างเดียวไม่ได้เขียนโดยวิธีการอื่นใดนอกจากตัวสร้าง

เพิ่มเติมเกี่ยวกับทั้งสองอธิบายไว้ที่นี่ในบทความนี้


1

โดยเฉพาะอย่างยิ่ง; คุณสามารถกำหนดค่าให้กับเขตข้อมูลแบบอ่านอย่างเดียวแบบคงที่ให้กับค่าที่ไม่คงที่ในขณะที่ค่าคงที่จะต้องกำหนดค่าคงที่


1

Const และอ่านอย่างเดียวมีความคล้ายคลึงกัน แต่ไม่เหมือนกันทุกประการ เขตข้อมูล const เป็นค่าคงที่เวลารวบรวมซึ่งหมายความว่าค่านั้นสามารถคำนวณได้ในเวลารวบรวม ฟิลด์แบบอ่านอย่างเดียวทำให้เกิดสถานการณ์เพิ่มเติมซึ่งต้องใช้รหัสบางอย่างระหว่างการสร้างประเภท หลังจากการก่อสร้างฟิลด์แบบอ่านอย่างเดียวไม่สามารถเปลี่ยนแปลงได้

ตัวอย่างเช่นสมาชิก const สามารถใช้เพื่อกำหนดสมาชิกเช่น:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

เนื่องจากค่าเช่น 3.14 และ 0 เป็นค่าคงที่เวลาคอมไพล์ อย่างไรก็ตามพิจารณากรณีที่คุณกำหนดประเภทและต้องการให้อินสแตนซ์ pre-fab บางอย่างของมัน ตัวอย่างเช่นคุณอาจต้องการกำหนดคลาสสีและให้ "ค่าคงที่" สำหรับสีทั่วไปเช่นสีดำสีขาว ฯลฯ คุณไม่สามารถทำสิ่งนี้กับสมาชิก const เนื่องจากด้านขวามือไม่ใช่ค่าคงที่เวลาคอมไพล์ หนึ่งสามารถทำได้กับสมาชิกคงที่ปกติ:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

แต่ก็ไม่มีอะไรที่จะป้องกันไม่ให้ลูกค้าของสีจากการล้อเล่นกับมันบางทีโดยการเปลี่ยนค่าสีดำและสีขาว ไม่จำเป็นต้องพูดสิ่งนี้จะทำให้เกิดความหวาดกลัวสำหรับลูกค้ารายอื่น ๆ ของคลาสสี คุณลักษณะ "อ่านอย่างเดียว" กล่าวถึงสถานการณ์นี้ เพียงแค่แนะนำคำหลักแบบอ่านอย่างเดียวในการประกาศเราจะรักษาความยืดหยุ่นในการเริ่มต้นในขณะที่ป้องกันไม่ให้ลูกค้ารหัสการล้อเล่น

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

เป็นที่น่าสนใจที่จะทราบว่าสมาชิก const มักจะคงที่ในขณะที่สมาชิกแบบอ่านอย่างเดียวอาจเป็นแบบคงที่หรือไม่เช่นเดียวกับเขตข้อมูลปกติ

เป็นไปได้ที่จะใช้คำหลักเดียวสำหรับสองวัตถุประสงค์นี้นำไปสู่ปัญหาการกำหนดเวอร์ชันหรือปัญหาประสิทธิภาพ สมมติว่าเราใช้คำหลักคำเดียวสำหรับ (const) นี้และผู้พัฒนาเขียน:

public class A
{
    public static const C = 0;
}

และนักพัฒนาซอฟต์แวร์คนอื่นเขียนโค้ดที่ใช้ A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

ตอนนี้โค้ดที่สร้างขึ้นสามารถขึ้นอยู่กับความจริงที่ว่า AC เป็นค่าคงที่เวลารวบรวมได้หรือไม่? คือสามารถใช้ AC แทนค่า 0 ได้หรือไม่? หากคุณพูดว่า "ใช่" นี่หมายความว่าผู้พัฒนา A ไม่สามารถเปลี่ยนวิธีการเริ่มต้น AC ได้ - สิ่งนี้จะอยู่ในมือของผู้พัฒนา A โดยไม่ได้รับอนุญาต หากคุณพูดว่า "ไม่" สำหรับคำถามนี้การเพิ่มประสิทธิภาพที่สำคัญจะพลาดไป บางทีผู้เขียน A อาจเป็นบวกว่า AC จะเป็นศูนย์เสมอ การใช้ทั้ง const และอ่านอย่างเดียวทำให้นักพัฒนา A สามารถระบุเจตนาได้ สิ่งนี้ทำให้เกิดพฤติกรรมการกำหนดเวอร์ชันที่ดีขึ้นและประสิทธิภาพที่ดีขึ้น


1

อ่านอย่างเดียว: ค่าจะเริ่มต้นได้เพียงครั้งเดียวจากตัวสร้างของคลาส
const: สามารถเริ่มต้นได้ในฟังก์ชั่นใด ๆ แต่เพียงครั้งเดียว


1

ความแตกต่างคือค่าของฟิลด์สแตติกแบบอ่านอย่างเดียวถูกตั้งค่า ณ รันไทม์ดังนั้นจึงสามารถมีค่าแตกต่างกันสำหรับการประมวลผลโปรแกรมที่แตกต่างกัน อย่างไรก็ตามค่าของฟิลด์ const ถูกตั้งค่าเป็นค่าคงที่เวลารวบรวม

เตือนความจำ: สำหรับประเภทการอ้างอิงทั้งสองกรณี (แบบคงที่และอินสแตนซ์) ตัวแก้ไขแบบอ่านอย่างเดียวจะป้องกันคุณจากการกำหนดการอ้างอิงใหม่ไปยังฟิลด์ มันไม่ได้ทำให้วัตถุที่ชี้โดยอ้างอิงไม่เปลี่ยนรูป

สำหรับรายละเอียดโปรดอ้างอิงคำถามที่พบบ่อย C # ในหัวข้อนี้: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx


1

ตัวแปรคงที่จะประกาศและเริ่มต้น ณ เวลารวบรวม ค่าไม่สามารถเปลี่ยนแปลงได้หลังจากหอผู้ป่วย ตัวแปรแบบอ่านอย่างเดียวจะเริ่มต้นได้จากตัวสร้างสแตติกของคลาสเท่านั้น อ่านอย่างเดียวจะใช้เฉพาะเมื่อเราต้องการกำหนดค่าในขณะดำเนินการ


1

Const : ค่าคงที่ที่แน่นอนในช่วงอายุการใช้งาน

อ่านอย่างเดียว : สามารถเปลี่ยนแปลงได้ในเวลาทำงาน


1
คำจำกัดความของคุณของ 'อ่านอย่างเดียว' ที่สามารถเปลี่ยนแปลงนั้นมีข้อบกพร่อง ฉันเดาว่า 'เปลี่ยน' คุณหมายถึง 'set' เช่น 'สามารถตั้งค่าได้ที่ runtime'
อาเหม็ด

0

สิ่งหนึ่งที่จะเพิ่มในสิ่งที่ผู้คนได้กล่าวไว้ข้างต้น หากคุณมีแอสเซมบลีที่ประกอบด้วยค่าแบบอ่านอย่างเดียว (เช่นอ่านอย่างเดียว MaxFooCount = 4;) คุณสามารถเปลี่ยนค่าที่เรียกแอสเซมบลีดูโดยส่งรุ่นใหม่ของแอสเซมบลีนั้นด้วยค่าที่แตกต่างกัน (เช่น MaxFooCount = 5

แต่ด้วย const มันจะถูกพับเป็นรหัสของผู้โทรเมื่อมีการรวบรวมผู้โทร

หากคุณมีความเชี่ยวชาญในระดับ C # ถึงระดับนี้คุณก็พร้อมสำหรับหนังสือของ Bill Wagner ที่มีประสิทธิภาพ C #: 50 วิธีเฉพาะในการปรับปรุง C # ของคุณซึ่งตอบคำถามนี้โดยละเอียด (และอีก 49 สิ่ง)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.