เป็นไปได้ไหมที่จะเขียนบางสิ่งที่คล้ายกับข้อความต่อไปนี้?
public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
เป็นไปได้ไหมที่จะเขียนบางสิ่งที่คล้ายกับข้อความต่อไปนี้?
public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
คำตอบ:
ใช่ แต่คุณต้องประกาศreadonly
แทนconst
:
public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
เหตุผลคือconst
สามารถนำไปใช้กับเขตข้อมูลที่มีค่าเป็นที่รู้จักในเวลารวบรวม เครื่องมือเตรียมใช้งานอาร์เรย์ที่คุณแสดงไม่ใช่นิพจน์คงที่ใน C # ดังนั้นจึงเกิดข้อผิดพลาดของคอมไพเลอร์
การประกาศว่าจะreadonly
แก้ปัญหาได้เนื่องจากค่าไม่ได้เริ่มต้นจนถึงเวลาใช้งาน (แม้ว่าจะรับประกันว่าจะได้รับการเริ่มต้นก่อนที่จะใช้อาร์เรย์ครั้งแรก)
ขึ้นอยู่กับว่าคุณต้องการบรรลุเป้าหมายในท้ายที่สุดคุณอาจพิจารณาประกาศ enum:
public enum Titles { German, Spanish, Corrects, Wrongs };
readonly static
มีความคล้ายคลึงกันของความหมายที่ร้องขอใด ๆ
static
ไม่จำเป็นต้องที่จะทำให้มันทำงานก็เพียงแค่เพิ่มความเป็นไปได้ที่จะอ้างอิงTitles
ได้โดยไม่ต้องยกตัวอย่างเช่น แต่ลบไปได้ที่จะคุ้มค่าการเปลี่ยนแปลงสำหรับอินสแตนซ์ที่แตกต่างกัน (เช่นคุณสามารถมีคอนสตรัคกับพารามิเตอร์ซึ่งขึ้นอยู่กับคุณเปลี่ยนค่าของreadonly
ฟิลด์)
คุณสามารถประกาศอาร์เรย์เป็นreadonly
แต่โปรดจำไว้ว่าคุณสามารถเปลี่ยนองค์ประกอบของreadonly
อาร์เรย์
public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";
พิจารณาใช้ enum ตามที่ Cody แนะนำหรือ IList
public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
const
ไม่ใช่readonly
...
คุณไม่สามารถสร้างอาร์เรย์ 'const' ได้เนื่องจากอาร์เรย์เป็นวัตถุและสามารถสร้างได้ในขณะใช้งานจริงเท่านั้น
คุณสามารถทำอะไรแทนการประกาศอาร์เรย์ของคุณเป็น "อ่านอย่างเดียว" สิ่งนี้มีผลเช่นเดียวกับ const ยกเว้นค่าสามารถตั้งค่าได้ที่รันไทม์ สามารถตั้งค่าได้เพียงครั้งเดียวและหลังจากนั้นจะมีค่าแบบอ่านอย่างเดียว (เช่น const)
const int[] a = null;
คือไม่มีประโยชน์มาก แต่เป็นตัวอย่างของค่าคงที่ของอาร์เรย์
ตั้งแต่ C # 6 คุณสามารถเขียนได้เช่น:
public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };
ดูเพิ่มเติมที่: C #: C # 6.0 ที่ปรับปรุงใหม่ (เฉพาะตอน "ฟังก์ชั่นและคุณสมบัติของ Expression Bodied")
สิ่งนี้จะทำให้คุณสมบัติสแตติกแบบอ่านอย่างเดียว แต่ยังคงช่วยให้คุณสามารถเปลี่ยนเนื้อหาของอาเรย์ที่ส่งคืน แต่เมื่อคุณเรียกคุณสมบัติอีกครั้งคุณจะได้รับอาเรย์ดั้งเดิมที่ไม่เปลี่ยนแปลงอีกครั้ง
สำหรับการชี้แจงรหัสนี้เป็นเช่นเดียวกับ (หรือจริงชวเลขสำหรับ):
public static string[] Titles
{
get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}
โปรดทราบว่ามีข้อเสียของวิธีการนี้: อาร์เรย์ใหม่นั้นมีการสร้างอินสแตนซ์สำหรับแต่ละการอ้างอิงดังนั้นถ้าคุณใช้อาร์เรย์ที่มีขนาดใหญ่มากนี่อาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่ถ้าคุณใช้อาร์เรย์เดิมอีกครั้ง (โดยใส่ไว้ในแอตทริบิวต์ส่วนตัวเช่น) มันจะเปิดโอกาสในการเปลี่ยนเนื้อหาของอาร์เรย์อีกครั้ง
หากคุณต้องการมีอาร์เรย์ (หรือรายการ) ที่ไม่เปลี่ยนรูปแบบคุณสามารถใช้:
public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };
แต่สิ่งนี้ยังมีความเสี่ยงต่อการเปลี่ยนแปลงเนื่องจากคุณยังสามารถส่งกลับไปยังสตริง [] และแก้ไขเนื้อหาได้เช่น:
((string[]) Titles)[1] = "French";
Titles[0]
ตัวอย่างเช่น - ในกรณีความพยายามในการมอบหมายนั้นถูกเพิกเฉยอย่างเงียบ ๆ เมื่อรวมกับความไร้ประสิทธิภาพของการสร้างอาร์เรย์ใหม่ทุกครั้งฉันสงสัยว่าวิธีการนี้น่าจะคุ้มค่าหรือไม่ ในทางตรงกันข้ามวิธีที่ 2 นั้นมีประสิทธิภาพและคุณต้องออกไปเพื่อเอาชนะความไม่สามารถเปลี่ยนแปลงได้
หากคุณประกาศอาร์เรย์ที่อยู่เบื้องหลังส่วนต่อประสาน IReadOnlyList คุณจะได้รับอาร์เรย์คงที่พร้อมค่าคงที่ที่ประกาศ ณ รันไทม์:
public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };
พร้อมใช้งานใน. NET 4.5 และสูงกว่า
.NET Framework v4.5 + วิธีการแก้ปัญหาที่ช่วยเพิ่มในคำตอบของ tdbeckett :
using System.Collections.ObjectModel;
// ...
public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);
หมายเหตุ: ระบุว่าคอลเลกชันจะคงแนวคิดก็อาจทำให้ความรู้สึกที่จะทำให้มันstatic
ที่จะประกาศได้ในระดับระดับ
ข้างบน:
เตรียมข้อมูลเบื้องต้นให้กับเขตข้อมูลสำรองโดยนัยของคุณสมบัติหนึ่งครั้งด้วยอาร์เรย์
หมายเหตุ{ get; }
- คือประกาศเพียงคุณสมบัติทะเยอทะยาน - เป็นสิ่งที่ทำให้คุณสมบัติตัวเองโดยปริยายอ่านอย่างเดียว (พยายามที่จะรวมreadonly
กับ{ get; }
เป็นจริงไวยากรณ์ผิดพลาด)
หรือคุณสามารถละเว้น { get; }
และเพิ่มreadonly
เพื่อสร้างเขตข้อมูลแทนคุณสมบัติเช่นเดียวกับคำถาม แต่การเปิดเผยให้สมาชิกข้อมูลสาธารณะเป็นคุณสมบัติแทนที่จะเป็นเขตข้อมูลเป็นนิสัยที่ดีในการสร้าง
สร้างอาร์เรย์เหมือนโครงสร้าง (ให้เข้าถึงการจัดทำดัชนี ) ที่เป็นจริงและทนทานอ่านอย่างเดียว (แนวคิดคงสร้างครั้งเดียว), ความเคารพทั้งที่มี:
IReadOnlyList<T>
วิธีการแก้ปัญหาที่หล่อสามารถนำมาใช้เพื่อให้เข้าถึงการเขียนไปยังองค์ประกอบดังแสดงในคำตอบที่เป็นประโยชน์ mjepsen ของ .
ช่องโหว่เช่นเดียวกับอินเตอร์เฟซซึ่งแม้จะมีความคล้ายคลึงกันในชื่อ เพื่อชั้น , ไม่ได้สนับสนุนการจัดทำดัชนีการเข้าถึงทำให้มันเป็นพื้นฐานที่ไม่เหมาะสมสำหรับการให้อาร์เรย์เช่นการเข้าถึง.)(string[])
IReadOnlyCollection<T>
ReadOnlyCollection
IReadOnlyCollection
ไม่รองรับการเข้าถึงที่จัดทำดัชนีดังนั้นจึงไม่สามารถใช้ที่นี่ได้ นอกจากนี้เช่นIReadOnlyList
(ซึ่งจะมีการจัดทำดัชนีการเข้าถึง) string[]
มันเป็นความเสี่ยงที่จะจัดการองค์ประกอบโดยการหล่อกลับไป ในคำอื่น ๆ : ReadOnlyCollection
(ซึ่งคุณไม่สามารถทอดอาเรย์สตริงไป) เป็นทางออกที่แข็งแกร่งที่สุด การไม่ใช้ getter เป็นตัวเลือก (และฉันได้อัปเดตคำตอบเพื่อให้ทราบแล้ว) แต่ด้วยข้อมูลสาธารณะน่าจะดีกว่าถ้าใช้คุณสมบัติ
สำหรับความต้องการของฉันฉันกำหนดstatic
อาร์เรย์แทนเป็นไปไม่ได้const
และใช้งานได้:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
const
จากตัวอย่าง OP แล้วยังใช้งานได้ แต่นั่น (หรือคำตอบของคุณ) อนุญาตให้เปลี่ยนทั้ง: Titles
อินสแตนซ์และค่าใด ๆ ดังนั้นคำตอบในประเด็นนี้คืออะไร?
readonly
คุณสามารถใช้แนวทางที่แตกต่าง: กำหนดสตริงคงที่เพื่อเป็นตัวแทนอาร์เรย์ของคุณแล้วแยกสตริงเป็นอาร์เรย์เมื่อคุณต้องการเช่น
const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');
วิธีนี้ช่วยให้คุณมีค่าคงที่ซึ่งสามารถเก็บไว้ในการกำหนดค่าและแปลงเป็นอาร์เรย์เมื่อจำเป็น
เพื่อความสมบูรณ์ขณะนี้เรายังมี ImmutableArays ในการกำจัดของเรา สิ่งนี้ควรจะไม่เปลี่ยนรูปอย่างแท้จริง:
public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });
ต้องใช้ System.Collections การอ้างอิง NuGet ที่ไม่น่าเชื่อ
https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx
นี่คือวิธีการทำสิ่งที่คุณต้องการ:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}
มันคล้ายกันมากกับการทำอาเรย์แบบอ่านอย่างเดียว
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; ไม่จำเป็นต้องสร้างรายการใหม่ทุกครั้งที่ดึงข้อมูลหากคุณกำหนดให้เป็น ReadOnlyCollection
นี่เป็นคำตอบเดียวที่ถูกต้อง คุณไม่สามารถทำได้ในขณะนี้
คำตอบอื่น ๆ ทั้งหมดแนะนำให้ใช้ตัวแปรแบบอ่านอย่างเดียวแบบสแตติกซึ่งคล้ายกับแต่ไม่เหมือนกับค่าคงที่ ค่าคงที่จะถูกเข้ารหัสอย่างหนักในชุดประกอบ ตัวแปรแบบอ่านอย่างเดียวแบบสแตติกสามารถตั้งค่าได้หนึ่งครั้งอาจเป็นเพราะวัตถุถูกเริ่มต้น
บางครั้งสิ่งเหล่านี้สามารถใช้แทนกันได้ แต่ไม่เสมอไป
ฉันเชื่อว่าคุณทำได้เพียงอ่านอย่างเดียว
อาเรย์อาจเป็นหนึ่งในสิ่งเหล่านั้นที่สามารถประเมินได้ที่รันไทม์เท่านั้น ค่าคงที่จะต้องประเมินในเวลารวบรวม ลองใช้ "อ่านอย่างเดียว" แทน "const"
เพื่อเป็นทางเลือกในการแก้ไขปัญหาองค์ประกอบที่สามารถแก้ไขได้ด้วยอาเรย์แบบอ่านอย่างเดียวคุณสามารถใช้คุณสมบัติคงที่แทน (องค์ประกอบแต่ละอย่างยังคงสามารถเปลี่ยนแปลงได้ แต่การเปลี่ยนแปลงเหล่านี้จะทำในสำเนาภายในของอาร์เรย์เท่านั้น)
public static string[] Titles
{
get
{
return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
}
}
แน่นอนว่าสิ่งนี้จะไม่มีประสิทธิภาพโดยเฉพาะอย่างยิ่งเนื่องจากมีการสร้างอาร์เรย์สตริงใหม่ทุกครั้ง
ทางเลือกที่ดีที่สุด:
public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };