int [] เป็นประเภทอ้างอิงหรือประเภทค่า?


124

ฉันรู้ว่า int เป็นประเภทค่า แต่อาร์เรย์ประเภทค่าคืออะไร ประเภทอ้างอิง? ประเภทมูลค่า? ฉันต้องการส่งอาร์เรย์ไปยังฟังก์ชันเพื่อตรวจสอบบางสิ่ง ฉันควรส่งอาร์เรย์หรือไม่เพราะมันจะผ่านการอ้างอิงของมันหรือฉันควรจะส่งผ่านเป็น ref?


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

11
@ darkassassin93: การส่งผ่านโดยการอ้างอิงหรือตามค่าไม่เกี่ยวข้องกับสิ่งที่เป็นประเภทอ้างอิงหรือประเภทค่า (ประเภทค่าสามารถส่งผ่านได้โดยการอ้างอิงและประเภทการอ้างอิงสามารถส่งผ่านได้ด้วยค่า)
LukeH

2
ในกรณีส่วนใหญ่ถ้าคุณสามารถเก็บ [null] ไว้ในฟิลด์หรือตัวแปรคุณสามารถสันนิษฐานได้ว่าเป็นประเภทอ้างอิง ข้อยกเว้นอย่างแน่นอนคือประเภทที่เป็นโมฆะ (Nullable <int> หรือ int?) เช่นเดียวกับสตริง
Noel Widmer

3
@ NoëlWidmer Strings ไม่ใช่ข้อยกเว้น: เป็นประเภทอ้างอิง
Arthur Castro

2
@ArthurCastro Argree ถึง 50%: สตริงที่สืบทอดมาจากคลาสซึ่งหมายความว่าเป็นประเภทอ้างอิง อย่างไรก็ตามความเท่าเทียมกันนั้นขึ้นอยู่กับเอกลักษณ์ (การเปรียบเทียบมูลค่า) มากกว่าการอ้างอิงและพฤติกรรมการส่งผ่านของพวกเขาจะถูกลบล้างเพื่อให้ตรงกับพฤติกรรมของประเภทค่า โดยทั่วไปแล้วเป็นประเภทอ้างอิงตามคำจำกัดความ แต่มีพฤติกรรมเหมือนประเภทค่าโดยการนำไปใช้
Noel Widmer

คำตอบ:


201

อาร์เรย์เป็นกลไกที่ช่วยให้คุณจัดการหลายรายการเป็นคอลเลกชันเดียว Microsoft® .NET Common Language Runtime (CLR) สนับสนุนอาร์เรย์แบบมิติเดียวอาร์เรย์หลายมิติและอาร์เรย์แบบหยัก (อาร์เรย์ของอาร์เรย์) ประเภทอาร์เรย์ทั้งหมดได้มาโดยปริยายจาก System.Array ซึ่งมาจาก System.Object ซึ่งหมายความว่า อาร์เรย์ทั้งหมดเป็นประเภทอ้างอิง ที่จัดสรรบนฮีปที่มีการจัดการเสมอและตัวแปรของแอปของคุณมีการอ้างอิงไปยังอาร์เรย์ไม่ใช่อาร์เรย์เอง

https://msdn.microsoft.com/en-us/library/bb985948.aspx


54
ชนิดค่าที่สืบทอดมาจาก System.ValueType ซึ่งสืบทอดมาจาก System.Object ดังนั้นเพียงเพราะ Array มาจาก System.Object ไม่ได้หมายความว่าเป็นประเภทอ้างอิง สิ่งที่ทำให้ System.Array เป็นประเภทอ้างอิงคืออินสแตนซ์จะถูกคัดลอกโดยการอ้างอิง IOW ให้ความสำคัญกับข้อเท็จจริงที่ว่า System.Array เป็นคลาส นั่นคือสิ่งที่ทำให้เป็นประเภทอ้างอิง
P. Brian Mackey

8
<nitpick> ฉันรู้ว่ามันอาจดูเหมือนว่าเอกสารนั้นกำลังบอกเป็นนัยว่า System.Array ที่มาจาก System.Object ทำให้เป็นประเภทอ้างอิง แม้ว่าประเภทใด ๆ ที่มาจาก System.Object อาจไม่เป็นความจริง แต่ข้อยกเว้นเดียวของกฎนี้คือ System.ValueType ซึ่งคอมไพเลอร์จะปฏิบัติแตกต่างกัน </nitpick>
Yannick Motton

ลิงค์ด้านบนเสีย นี่คือลิงค์msdn
MUG4N

สิ่งใดก็ตามที่มาจาก System.Object เป็นประเภทการอ้างอิง UNLESS ยังมาจาก System.ValueType @ P. Brian.Mackey เพียงเพราะ type เป็น class ไม่ได้หมายความว่าเป็นประเภทอ้างอิงเพราะเบื้องหลังโครงสร้างเป็นเพียงคลาสที่มาจาก System.ValueType
David Klempfner

31

การทดสอบประเภทอ้างอิงเทียบกับชนิดค่าที่ง่ายที่สุดคือชนิดอ้างอิงได้nullแต่ประเภทค่าไม่สามารถทำได้


47
... ยกเว้นประเภทค่าที่เป็นโมฆะซึ่งเป็นโมฆะได้ (คุณสามารถตั้งค่าเป็นค่าว่างซึ่งหมายถึงค่าว่างสำหรับประเภทแทนที่จะเป็นการอ้างอิงแบบ null ) และยังคงเป็นประเภทค่า
Jon Skeet

1
ไม่เคยคิดที่จะทำเช่นนั้นเมื่อพยายามทำความเข้าใจว่าเป็นประเภทคุณค่าหรือไม่! ความคิดที่ดี.
กินเอลิเซียม


6

ก่อนอื่นฉันอยากจะบอกคุณว่า Array เป็นประเภทอ้างอิง ทำไม? ฉันอธิบายโยนตัวอย่างหนึ่งตรงนี้

ตัวอย่าง:

int val = 0; // this is a value type ok
int[] val1 = new int[20] // this is a reference type because space required to store 20 integer value that make array allocated on the heap.

นอกจากนี้ประเภทการอ้างอิงยังสามารถเป็นค่าว่างได้ในขณะที่ประเภทค่าไม่สามารถทำได้

ประเภทค่าที่จัดเก็บใน Stack และประเภทการอ้างอิงที่จัดเก็บใน Heap

คุณสามารถส่งอาร์เรย์ไปยังฟังก์ชันโดยใช้ out หรือ ref วิธีการเริ่มต้นเท่านั้นที่แตกต่างกัน

มากกว่า..


3

ทดสอบเพื่อตรวจสอบว่าเป็นการอ้างอิงหรือประเภทค่า:

// we create a simple array of int
var a1 = new int[]{1,2,3};
// copy the array a1 to a2
var a2 = a1;
// modify the first element of a1
a1[0]=2;
// output the first element of a1 and a2
Console.WriteLine("a1:"+a1[0]); // 2
Console.WriteLine("a2:"+a2[0]); // 2
//**************************
// all the two variable point to the same array
// it's reference type!
//**************************

คุณสามารถทดสอบออนไลน์ได้ที่https://dotnetfiddle.net/UWFP45


2
การสร้างอาร์เรย์จะง่ายกว่าและพยายามกำหนดให้เป็นโมฆะ การรวบรวมจะล้มเหลวหากเป็นประเภทค่า ..
กลืน elysium

ได้รับการเตือนล่วงหน้า เมื่อปล่อย C # 8 แล้วมันก็จะล้มเหลวเช่นกันหากคุณใช้คุณลักษณะการอ้างอิงที่เป็นโมฆะเนื่องจากประเภทการอ้างอิงที่ไม่เป็นโมฆะไม่สามารถยอมรับค่าว่างได้เช่นกัน
Mark A. Donohoe

2

อาร์เรย์เองเป็นชนิดอ้างอิง ค่าของอาร์เรย์นั้นคือค่าหรือประเภทการอ้างอิงตามที่กำหนดโดยชนิดข้อมูลอาร์เรย์ ในตัวอย่างของคุณอาร์เรย์คือประเภทการอ้างอิงและค่าคือประเภทค่า

ทั้งหมดเดียวมิติอาร์เรย์โดยปริยายใช้IList<T>ที่<T>เป็นชนิดข้อมูลของอาร์เรย์ คุณสามารถใช้อินเทอร์เฟซนั้นเป็นชนิดข้อมูลของพารามิเตอร์วิธีการของคุณแทนได้ คุณยังสามารถใช้IEnumerable<T>สำหรับประเภทข้อมูล ไม่ว่าในกรณีใด (หรือแม้ว่าคุณจะใช้เพียงอย่างเดียวint[]) คุณไม่จำเป็นต้องส่งผ่านเป็นrefพารามิเตอร์อย่างชัดเจน


0

// การอ้างอิงไปยังอาร์เรย์ถูกส่งผ่านด้วยค่า นี่คือที่มาของความ :-) สับสน ...

        int[] test = { 1, 2, 3, 4 };

        modifContenuSansRef(test);
        Console.WriteLine(test[0]); // OK --> 99 le contenu du tableau est modifié

        modifTailleSansRef(test);
        Console.WriteLine(test.Length); // KO --> 4 La taille n'est pas modifiée

    }

    static void modifContenuSansRef(int[] t)
    {
        t[0] = 99;
    }

    static void modifTailleSansRef(int[] t)
    {
        Array.Resize(ref t, 8);
    }

0

อาร์เรย์เป็นชนิดอ้างอิงเสมอไม่สำคัญว่าอาร์เรย์จะมีประเภทค่าเช่น int หรือชนิดการอ้างอิงเช่นสตริงเมื่อคุณประกาศอาร์เรย์เช่น

int[] integers=new int[10];

ตัวแปรจำนวนเต็มมีเพียงการอ้างอิงไปยังอาร์เรย์ซึ่งจะอยู่ในฮีป

นอกจากนี้ยังมีหลายคนพูดถึงว่าคุณอาจแตกต่างประเภทค่าจากประเภทการอ้างอิงเพียงขึ้นอยู่กับความจริงที่ว่าตัวแปรอาจเป็นโมฆะหรือไม่ก็ได้ ฉันอยากจะพูดถึงว่าในประเภทค่าปัจจุบันของ c # สามารถเป็นค่าว่างได้

เช่น

int? integer=null

และไม่ใช่วิธีที่ดีในการระบุประเภทคือการอ้างอิงหรือค่าขึ้นอยู่กับตัวแปร fact อาจเป็นโมฆะหรือไม่ก็ได้


-2

ข้อมูลเชิงลึกเพียงเล็กน้อย:

ตัวอย่างเช่นintแทนจำนวนเต็มเดียวint[]แทนอาร์เรย์ของจำนวนเต็ม

ในการเริ่มต้นอาร์เรย์ด้วยมิติข้อมูลเฉพาะคุณสามารถใช้newคำสำคัญโดยกำหนดขนาดไว้ในวงเล็บเหลี่ยมหลังชื่อประเภท:

//create a new array of 32 ints.
int[] integers = new int[32];

อาร์เรย์ทั้งหมดเป็นประเภทอ้างอิงและเป็นไปตามความหมายอ้างอิง ดังนั้นในรหัสนี้แม้ว่าแต่ละองค์ประกอบจะเป็นประเภทค่าดั้งเดิมintegersอาร์เรย์เป็นประเภทอ้างอิง ดังนั้นหากคุณเขียนในภายหลัง:

int[] copy = integers;

สิ่งนี้จะกำหนดสำเนาตัวแปรทั้งหมดเพื่ออ้างถึงอาร์เรย์เดียวกันโดยจะไม่สร้างอาร์เรย์ใหม่

ไวยากรณ์อาร์เรย์ของ C # มีความยืดหยุ่นช่วยให้คุณสามารถประกาศอาร์เรย์โดยไม่ต้องกำหนดค่าเริ่มต้นเพื่อให้อาร์เรย์มีขนาดแบบไดนามิกในโปรแกรมในภายหลัง ด้วยเทคนิคนี้โดยพื้นฐานแล้วคุณกำลังสร้างการอ้างอิงที่เป็นโมฆะและต่อมาก็ชี้การอ้างอิงนั้นไปยังตำแหน่งหน่วยความจำที่จัดสรรแบบไดนามิกที่ร้องขอด้วยnewคำสำคัญ

int[] integers;
integers = new int[32];

ขอบคุณ.

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