Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

การใช้ ref, out และคีย์เวิร์ดใน C # คืออะไร?


ใน C# เมธอดส่วนใหญ่สามารถมีพารามิเตอร์ตั้งแต่ศูนย์ขึ้นไป ซึ่งกำหนดข้อมูลที่ต้องระบุให้กับเมธอด รหัสใด ๆ ที่เรียกใช้เมธอดจะต้องส่งข้อมูล (เรียกว่าอาร์กิวเมนต์) ไปยังเมธอด เมธอดประกาศอินพุตเป็นพารามิเตอร์ และจัดเตรียมโดยการเรียกโค้ดในรูปแบบของอาร์กิวเมนต์

ตัวอย่างเช่น พิจารณาเมธอดต่อไปนี้และการเรียกเมธอดที่ตามมา

static void Greet(string greeting){
   Console.WriteLine(greeting);
}
...
Greet("Hello");

ในตัวอย่างข้างต้น การทักทายเป็นพารามิเตอร์ของวิธีการ Greet() และ "สวัสดี" เป็นอาร์กิวเมนต์ที่ส่งผ่านไปยังวิธีการนั้น

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

using System;
int number = 8;
Increase(number);
Console.WriteLine(number); // prints 8
static void Increase(int num){
   num = num + 1;
   Console.WriteLine(num); // prints 9
}

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

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
Promote(john);
Console.WriteLine(john.Salary); // prints 60000
static void Promote(User u){
   u.Salary += 10000;
   Console.WriteLine(u.Salary); // prints 60000
}

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

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
Promote(john);
Console.WriteLine(john.Salary); // prints 50000
static void Promote(User u){
   u = null;
}

C# อนุญาตให้ใช้คีย์เวิร์ดตัวปรับแต่งที่แตกต่างกันสามคำ ซึ่งคุณสามารถควบคุมพารามิเตอร์ของเมธอดได้

ตัวแก้ไขการอ้างอิง

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

ในตัวอย่างต่อไปนี้ การตั้งค่าอาร์กิวเมนต์ u เป็น null จะทำให้ตัวแปร john เป็น null ทำให้เกิดข้อยกเว้นการอ้างอิง null

ตัวอย่าง

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
Promote(ref john);
Console.WriteLine(john.Salary); // throws System.NullReferenceException
static void Promote(ref User u){
   u = null;
}

อาร์กิวเมนต์ที่ส่งผ่านด้วยตัวแก้ไขการอ้างอิงจะต้องเริ่มต้นก่อนที่จะส่งผ่าน

ตัวแก้ไขสัญญาณออก

คล้ายกับตัวแก้ไขการอ้างอิง ยกเว้น

  • อาร์กิวเมนต์ไม่จำเป็นต้องเริ่มต้นก่อนที่จะเข้าสู่ฟังก์ชัน

  • อาร์กิวเมนต์ต้องเริ่มต้น (กำหนดให้กับ) ก่อนจึงจะออกจากฟังก์ชันได้

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

using System;
Hire(out User john);
Console.WriteLine(john.Salary); // prints 50000
static void Hire(out User u){
   u = new User{
      Name = "John",
      Salary = 50000
   };
}

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

มักจะ ออก ตัวแปรถูกใช้เพื่อรับค่าส่งคืนหลายค่าจากฟังก์ชันดังนี้ -

using System;
var john = new User{
   Name = "John",
   Salary = 50000
};
bool shouldPromote = Raise(john.Salary, out double hike);
Console.WriteLine(shouldPromote); // True
Console.WriteLine($"Hike Amount = {hike}"); // prints 5000
static bool Raise(int salary, out double hike){
   hike = salary * 0.1;
   return hike < 7000;
}

ตัวแก้ไขใน

คล้ายกับ ref และ ออก พารามิเตอร์ ยกเว้นวิธีการที่ยอมรับ ใน ค่าของอาร์กิวเมนต์ไม่สามารถแก้ไขอาร์กิวเมนต์ได้ หากพยายาม คอมไพเลอร์ C# จะสร้างข้อผิดพลาดในการคอมไพล์

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

var point = new Coord();
Verify(point);
static void Verify(in Coord c){
   // error: Cannot assign to variable 'in Coord' because it is a readonly variable
   c = new Coord();
}
struct Coord{
   public int X;
   public int Y;
}

ตัวอย่าง

using System;
class Program{
   static void Main(){
      int number = 8;
      Increase(number);
      Console.WriteLine(number); // prints 8
      var john = new User { Name = "John", Salary = 50000 };
      Promote(john);
      Console.WriteLine(john.Salary); // prints 60000
      Leave(john);
      Console.WriteLine(john.Salary); // prints 60000

      LeaveByRef(ref john);
      Console.WriteLine(john?.Salary); // prints nothing

      User dave;
      Hire(out dave);
      Console.WriteLine(dave.Salary); // prints 50000
   }
   static void Increase(int num){
      num = num + 1;
      Console.WriteLine(num); // prints 9
   }
   static void Promote(User u){
      u.Salary += 10000;
      Console.WriteLine(u.Salary); // prints 60000
   }
   static void Leave(User u){
      u = null;
   }
   static void LeaveByRef(ref User u){
      u = null;
   }
   static void Hire(out User u){
      u = new User{
         Name = "John",
         Salary = 50000
      };  
   }
}
class User{
   public string Name { get; set; }
   public int Salary { get; set; }
}

ผลลัพธ์

9
8
60000
60000
60000
50000