ฉันจะเริ่มต้นอาร์เรย์ว่างใน C # ได้อย่างไร


328

เป็นไปได้หรือไม่ที่จะสร้างอาร์เรย์ว่างโดยไม่ระบุขนาด?

ตัวอย่างเช่นฉันสร้าง:

String[] a = new String[5];

เราสามารถสร้างอาเรย์สตริงข้างต้นโดยไม่มีขนาดได้หรือไม่?


2
stackoverflow.com/questions/151936/...ยูตรวจสอบการเชื่อมโยงนี้อาจช่วยให้คุณเข้าใจสิ่งอาร์เรย์อย่างชัดเจน
ราวี Gadag

คำตอบ:


435

หากคุณจะใช้คอลเลกชันที่คุณไม่ทราบขนาดล่วงหน้ามีตัวเลือกที่ดีกว่าอาร์เรย์

ใช้List<string>แทน - มันจะช่วยให้คุณเพิ่มรายการได้มากเท่าที่คุณต้องการและถ้าคุณต้องการส่งกลับอาร์เรย์เรียกToArray()ใช้ตัวแปร

var listOfStrings = new List<string>();

// do stuff...

string[] arrayOfStrings = listOfStrings.ToArray();

หากคุณต้องสร้างอาเรย์ที่ว่างเปล่าคุณสามารถทำได้:

string[] emptyStringArray = new string[0]; 

1
@Oded - สตริง [] emptyStringArray = สตริงใหม่ [0]; ไม่ส่งผลให้เกิดอาร์เรย์ว่างเปล่าใช่ไหม ดูเหมือนว่ามันเป็นอาร์เรย์ที่มีองค์ประกอบหนึ่งที่องค์ประกอบนั้นเป็นโมฆะ
rory.ap

11
@Roryap - ไม่มันให้ผลลัพธ์string[]ที่ไม่มีองค์ประกอบ หากคุณพยายามเข้าถึงemptyStringArray[0]คุณจะได้รับIndexOutOfRangeException
Oded

@Oded - ขอบคุณฉันค่อนข้างใหม่กับ C # ใน VB ดัชนีที่จัดเตรียมไว้มีขอบเขตบนไม่ใช่จำนวนขององค์ประกอบ
rory.ap

1
คุณจะพิจารณาอะไรดีกว่า: var strings = new string [] {}; หรือ var strings = new string [0]; BTW: ฉันพิจารณาอาร์เรย์ว่างเปล่าเป็นค่าเริ่มต้นที่ถูกต้องอย่างสมบูรณ์สำหรับพารามิเตอร์วิธี: โมฆะสาธารณะ EditItems (IEnumerable <Item> toEdit, IEnumerable <long> toDelete = ยาวใหม่ [] {})
realbart

6
@ RickO'Shea - C ++ ไม่ใช่ C # Stroustrup รู้ C ++ ของเขา - ไม่แน่ใจว่าเขารู้ C # และ NET GC ของเขา ไม่ต้องไปทำสงครามศาสนากับคุณ
Oded

181

ลองสิ่งนี้:

string[] a = new string[] { };

7
เมื่อขยายคำตอบนี้คุณยังสามารถเริ่มต้นอาร์เรย์ด้วยรายการโดยไม่ระบุขนาดหรือประเภทคอมไพเลอร์จะอนุมานจาก initializer: var a = new [] {"a", "b", "c"}; นี่ยังคงเป็นอาร์เรย์สตริงที่พิมพ์อย่างมาก
Nick VanderPyle

1
ข้อยกเว้น Unhandled: System.IndexOutOfRangeException: ดัชนีอยู่นอก boun ds ของอาร์เรย์ ที่ ArrayClass.Main (String [] args) ฉันพบข้อผิดพลาดนี้หลังจากฉันเปลี่ยน int [] variable = new int [] {}
yogesh

6
@yogesh: นั่นแปลก เมื่อตัวอย่างเช่นการเขียนint[] variable = new int[]{}และใช้มันสำหรับตัวอย่างเช่นในวงเช่นforeach (var s in variable){ Console.WriteLine(s);}รหัสจะรวบรวมเพื่อ: และint[] args1 = new int[0]; foreach (int num in args1){Console.WriteLine(num);}ดังนั้นจึงไม่ควรมีความแตกต่างระหว่างการใช้new int[0]และnew int[]{}ในขณะที่ทั้งสองได้รับการคอมไพล์ในรหัสเดียวกัน
Nope

1
@GlennGordon อย่างแน่นอน แต่เป็นของใหม่ในรุ่น C # 3.0 (ตั้งแต่ปี 2007 ด้วย Visual Studio 2008) เวอร์ชันนั้นยังอนุญาตให้ใช้รูปแบบง่าย ๆ อีกด้วยvarแม้ว่าจะใช้เฉพาะกับตัวแปรโลคัล (ไม่ใช่สำหรับฟิลด์) อย่างไรก็ตามใน C # 2.0 (Visual Studio 2005) และก่อนหน้านี้คุณต้องใช้ไวยากรณ์ของคำตอบนี้ (หรือstring[] a = new string[0];)
Jeppe Stig Nielsen

113

ใน. NET 4.6 วิธีที่แนะนำคือการใช้วิธีการใหม่Array.Empty:

String[] a = Array.Empty<string>();

การใช้งานนั้นรวบรัดโดยใช้วิธีที่สมาชิกแบบสแตติกในคลาสทั่วไปทำงานใน. Net :

public static T[] Empty<T>()
{
    return EmptyArray<T>.Value;
}

// Useful in number of places that return an empty byte array to avoid
// unnecessary memory allocation.
internal static class EmptyArray<T>
{
    public static readonly T[] Value = new T[0];
}

(รหัสสัญญาที่เกี่ยวข้องกับรหัสลบออกเพื่อความชัดเจน)

ดูสิ่งนี้ด้วย:


@Cole Johnson - ขอบคุณสำหรับการแก้ไข แต่ฉันย้อนกลับ ฉันละเว้นบรรทัดเหล่านี้โดยมีวัตถุประสงค์: ฉันต้องการพูดเพียงการใช้งานที่น่าสนใจ สัญญาโค้ดและคุณลักษณะต่าง ๆ จะช่วยให้คุณเข้าใจว่าเกิดอะไรขึ้น (ลิงก์ไปยังแหล่งข้อมูลนั้นมีทุกอย่างแน่นอน) ฉันได้เพิ่มบรรทัดใหม่ในความคิดเห็นเพื่อหลีกเลี่ยงการเลื่อนบน Stack Overflow ถ้าคุณไม่รังเกียจฉันชอบวิธีนี้ ขอบคุณ!
Kobi

2
การปรับปรุงอย่างชัดเจนสำหรับการอ่านจาก:Enumerable.Empty<T>().ToArray()
DanielV

แม้ว่าวิธีนี้จะเป็นที่ต้องการในกรณีส่วนใหญ่ แต่ก็ไม่ได้ตอบคำถามเดิม OP ต้องการสร้างอาร์เรย์ที่ว่างเปล่า Array.Empty<T>()ไม่ได้สร้างอาร์เรย์ มันจะส่งกลับการอ้างอิงไปยังอาร์เรย์ที่จัดสรรไว้ล่วงหน้า
l33t

33

คุณสามารถเริ่มต้นด้วยขนาด 0 แต่คุณจะต้องกำหนดค่าเริ่มต้นใหม่เมื่อคุณรู้ว่าขนาดคืออะไรเนื่องจากคุณไม่สามารถต่อท้ายอาร์เรย์ได้

string[] a = new string[0];

นี่คือคำตอบที่ถูกต้อง
abzarak

7

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

หากคุณต้องการกำหนดคอลเลกชันเมื่อคุณไม่ทราบว่าอาจมีขนาดเท่าใดอาร์เรย์อาจไม่ใช่ตัวเลือกของคุณ แต่มีList<T>ลักษณะคล้ายหรือคล้ายกัน

ที่กล่าวว่าวิธีเดียวที่จะประกาศอาร์เรย์โดยไม่ต้องระบุขนาดที่จะมีอาร์เรย์ว่างของขนาด 0 hemantและAlex Dnมีสองวิธี อีกทางเลือกที่ง่ายกว่าก็คือ :

string[] a = { };

[ องค์ประกอบภายในวงเล็บควรแปลงให้เป็นประเภทที่กำหนดโดยปริยายเช่นstring[] a = { "a", "b" }; ]

หรืออีกอย่าง:

var a = Enumerable.Empty<string>().ToArray();

นี่คือวิธีที่เปิดเผยมากขึ้น :

public static class Array<T>
{
    public static T[] Empty()
    {
        return Empty(0);
    }

    public static T[] Empty(int size)
    {
        return new T[size];
    }
}

ตอนนี้คุณสามารถโทร:

var a = Array<string>.Empty();

//or

var a = Array<string>.Empty(5);

1
ฉันไม่สามารถคิดถึงการใช้งานใด ๆ ยกเว้นเมื่อคุณต้องผ่านอาร์เรย์เป็นพารามิเตอร์ มีบางกรณีที่สะท้อนวิธีที่ยอมรับอาร์เรย์ของวัตถุและคุณอาจต้องการผ่านอาร์เรย์ว่างเปล่าเพื่อให้เกิดการกระทำเริ่มต้น ฉันจะแก้ไขคำตอบของฉัน
nawfal

ตัวอย่างเช่นคุณมีอินเทอร์เฟซที่นำไปใช้งานโดยคลาสต่างๆที่ส่งคืน IEnumerable และหนึ่งในการใช้งานนั้นไม่มีองค์ประกอบสำหรับวิธีการและส่งกลับอาร์เรย์ว่างตัวอย่างเช่น
Ignacio Soler Garcia

@IgnacioSolerGarcia ฉันจะส่งกลับอาร์เรย์ในกรณีนั้นถ้าหากเป็นแอปพลิเคชันที่มีประสิทธิภาพสูงมาก ฉันจะบอกว่าอาร์เรย์ล้าสมัยและควรหลีกเลี่ยงหากคุณทำได้ ดูสิ่งนี้โดย Lippertและคำถาม SO นี้
nawfal

โปรดทราบว่าประเภทที่ส่งคืนคือ IEnumerable ดังนั้นอาร์เรย์จึงเป็นแบบอ่านอย่างเดียวและไม่ได้มีไว้สำหรับเปลี่ยน เหตุใดฉันจะส่งคืนรายการในกรณีนี้เป็นตัวอย่าง
Ignacio Soler Garcia

1
กรณีการใช้งานสำหรับอาเรย์ที่ว่างเปล่านั้นเป็นเรื่องง่าย - เมื่อคุณต้องการเติมวัตถุและคุณไม่รู้ว่าคุณจะเพิ่มจำนวนเท่าใด
vapcguy

6

เรียบง่ายและสง่างาม!

string[] array = {}

ฉันจะเปลี่ยนarrayเป็นเพียงaเช่นเดียวarrayกับคำหลักเมื่อเป็นตัวพิมพ์ใหญ่ การฝึกฝนที่ไม่เหมาะสมในการใช้ชื่อคำหลักเป็นชื่อตัวแปร - แม้ว่ากรณีและปัญหาจะแตกต่างกัน และโดยทั่วไปเหมือนกับคำตอบของฉันยกเว้นที่ฉันString.Emptyมี
vapcguy

1
1. อาร์เรย์ไม่ใช่คำหลัก ac # อาร์เรย์เป็นชั้นและไม่ใช่คำหลักที่ 2 "เป็น" คือยังมีการปฏิบัติที่ไม่ดี (อาจจะเลวร้ายยิ่งการปฏิบัติที่เลวร้ายกว่าการใช้คำหลัก)
disklosr

เป็นเทคนิค คลาส, คีย์เวิร์ด, มันเป็นตัวกำหนดประเภทของวัตถุและยังไม่ดี ทำไมคุณคิดว่าaไม่ดี
vapcguy

1
เพราะชื่อตัวแปรที่ไม่มีคำอธิบายและตัวอักษรหนึ่งตัวเป็นสิ่งที่ไม่ดีเพราะมันไม่ได้อธิบายเหตุผลที่อยู่เบื้องหลัง "array" เป็นชื่อที่ดีกว่า "a" อย่างแน่นอน ชื่อที่ดีกว่าคือ "emptyArray"
disklosr

4

string[] a = new string[0];

หรือสัญกรณ์สั้น:

string[] a = { };

วิธีที่ต้องการตอนนี้คือ:

var a = Array.Empty<string>();

ฉันได้เขียนนิพจน์ปกติสั้น ๆ ที่คุณสามารถใช้ใน Visual Studio new string[0]ถ้าคุณต้องการที่จะเปลี่ยนความยาวเป็นศูนย์การจัดสรรเช่น ใช้ค้นหา (ค้นหา) ใน Visual Studio ที่เปิดใช้งานตัวเลือกนิพจน์ปกติ:

new[ ][a-zA-Z0-9]+\[0\]

ตอนนี้ค้นหาทั้งหมดหรือ F3 (ค้นหาถัดไป) และแทนที่ทั้งหมดด้วย Array.Empty <…> ()


3

คุณสามารถกำหนดขนาดอาร์เรย์ที่รันไทม์

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

Array a = Array.CreateInstance(typeof(string), 5);

4
ทำไมทำทุกอย่าง ที่รันไทม์คุณสามารถกำหนดขนาดของอาเรย์จากตัวแปรได้ตามปกติ:int i = 5; string[] a = new string[i];
Kevin Brock

ฉันเดาว่ายาชื่อสามัญดูเหมือนว่าจะล้าสมัยแล้ว
Radarbob

2

ฉันได้ลอง:

string[] sample = new string[0];

แต่ฉันสามารถแทรกหนึ่งสายเข้าไปในนั้นแล้วฉันได้รับข้อผิดพลาดข้อผิดพลาด OutOfBound ดังนั้นฉันเพียงแค่ใส่ขนาดมันเช่น

string[] sample = new string[100];

หรือวิธีอื่นที่เหมาะกับฉัน:

List<string> sample = new List<string>();

การกำหนดค่าสำหรับรายการ:

sample.Add(your input);

1

อย่างที่ฉันรู้ว่าคุณไม่สามารถสร้างอาร์เรย์ได้โดยไม่ต้องมีขนาด แต่คุณสามารถใช้ได้

List<string> l = new List<string>() 

l.ToArray()แล้วก็


1

การรวม @nawfal และคำแนะนำ @Kobi:

namespace Extensions
{
    /// <summary> Useful in number of places that return an empty byte array to avoid unnecessary memory allocation. </summary>
    public static class Array<T>
    {
        public static readonly T[] Empty = new T[0];
    }
}

ตัวอย่างการใช้งาน:

Array<string>.Empty

อัพเดท 2019-05-14

(เครดิตถึง @Jaider ty)

ใช้ดีกว่า. Net API:

public static T[] Empty<T> ();

https://docs.microsoft.com/en-us/dotnet/api/system.array.empty?view=netframework-4.8

นำไปใช้กับ:

.NET Core: 3.0 ดูตัวอย่าง 5 2.2 2.1 2.0 1.1 1.0

.NET Framework: 4.8 4.7.2 4.7.1 4.7 4.6.2 4.6.1 4.6

.NET Standard: 2.1 Preview 2.0 1.6 1.5 1.4 1.3

...

HTH


1
ใน. NET Core 2 มีส่วนขยายอยู่แล้วarr = Array.Empty<string>();
Jaider

iirc ใน. NetStandart [4.something] - นอกจากนี้ยังมี
ShloEmi

0

คุณทำได้:

string[] a = { String.Empty };

หมายเหตุ: OP หมายถึงไม่ต้องระบุขนาดไม่ทำให้อาร์เรย์ไม่มีขนาด


7
สิ่งนี้จะไม่สร้างอาร์เรย์สตริงที่มีความยาว 1 หรือไม่
Sumner Evans

จริง แต่ก็เคลียร์ และ OP ขอให้ประกาศอาร์เรย์โดยไม่ต้องระบุขนาด - นี่เหมาะกับที่
vapcguy

และนั่นเป็นสิ่งที่ควรลงเพราะเหตุใด OP หมายความว่าไม่ต้องมีขนาดไม่ทำให้อาร์เรย์specify sizeless
vapcguy

1
@ vapcguy ฉันเป็นผู้ลงมือ ฉันเสียใจมัน ฉันได้แก้ไขคำตอบของคุณเพื่อยกเลิกการโหวตของฉัน ความคิดเห็นของคุณทำให้คำถามค่อนข้างน่าสงสัย ไม่แน่ใจว่านั่นคือความหมายของ OP หรือไม่
nawfal

4
OP ขออาร์เรย์ที่ว่างเปล่า อาร์เรย์นี้ไม่ว่างเปล่า
Keith

0

นี่คือตัวอย่างโลกแห่งความจริง ในนี้มีความจำเป็นต้องเริ่มต้นอาร์เรย์foundFilesแรกที่มีความยาวเป็นศูนย์

(ดังที่เน้นในคำตอบอื่น ๆ : สิ่งนี้เริ่มต้นไม่ใช่องค์ประกอบและโดยเฉพาะอย่างยิ่งไม่ใช่องค์ประกอบที่มีดัชนีเป็นศูนย์เพราะนั่นหมายถึงอาร์เรย์มีความยาว 1 อาร์เรย์มีความยาวเป็นศูนย์หลังจากเส้นนี้!)

หาก= string[0]ละเว้นส่วนนี้จะมีข้อผิดพลาดของคอมไพเลอร์!

นี่เป็นเพราะการบล็อกการจับโดยไม่ต้องทำใหม่ คอมไพเลอร์ C # รับรู้ถึงเส้นทางของรหัสว่าฟังก์ชันDirectory.GetFiles()สามารถโยนข้อยกเว้นเพื่อให้อาร์เรย์ไม่สามารถกำหนดค่าเริ่มต้นได้

ก่อนที่จะมีใครบอกว่าอย่ารื้อฟื้นข้อยกเว้นนั้นจะเป็นการจัดการข้อผิดพลาดที่ไม่ดี: นี่ไม่ใช่ความจริง การจัดการข้อผิดพลาดต้องสอดคล้องกับข้อกำหนด

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

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

การเรียกเพื่อGetFiles(Dir)ปรับขนาดอาร์เรย์

string[] foundFiles= new string[0];
string dir = @"c:\";
try
{
    foundFiles = Directory.GetFiles(dir);  // Remark; Array is resized from length zero
}
// Please add appropriate Exception handling yourself
catch (IOException)
{
  Console.WriteLine("Log: Warning! IOException while reading directory: " + dir);
  // throw; // This would throw Exception to caller and avoid compiler error
}

foreach (string filename in foundFiles)
    Console.WriteLine("Filename: " + filename);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.