มีอะไรใหม่ใน .NET Core 2 และ C# 7 : ตัวกระทำ is กับ คุณสมบัติใหม่ในคำสั่ง switch และ Ref local

ตัวกระทำ is กับ คุณสมบัติใหม่ในคำสั่ง switch และ Ref local
ตัวกระทำ is
เริ่มในภาษาC# เวอร์ชั่น 7.0 ขึ้นไปตัวกระทำ is มีความสามารถเพิ่มจากเดิมเพื่อใช้ในงานตรวจสอบรูปแบบที่ซับซ้อนได้ดีขึ้นกว่าเดิม
ตัวกระทำ is ใช้หาชนิดของ type เพื่อตรวจสอบความเข้ากันได้ขณะ run โปรแกรม
มันทำหน้าที่ตรวจว่า object หรือ ผลลัพธ์จากนิพจน์สามารถแปลงไปเป็นชนิดข้อมูลที่กำหนดได้หรือไม่
มี syntax อย่างที่เห็นใน รูปที่ 1 บรรทัด 3
รูปที่ 1
ตัวกระทำ is ใช้หาชนิดของ type เพื่อตรวจสอบความเข้ากันได้ขณะ run โปรแกรม
มันทำหน้าที่ตรวจว่า object หรือ ผลลัพธ์จากนิพจน์สามารถแปลงไปเป็นชนิดข้อมูลที่กำหนดได้หรือไม่
มี syntax อย่างที่เห็นใน รูปที่ 1 บรรทัด 3
รูปที่ 1
คำว่า expr คือนิพจน์ที่จะถูกประเมินค่าไปเป็น type
type คือชื่อของ type ที่ต้องการตรวจสอบว่าตรงกันหรือเข้ากันได้กับ expr หรือไม่ ผลลัพธ์ที่ได้จากการทำงานจะเป็น true
ถ้า expr ไม่ใช่ค่า Null และ เป็น type ที่ตรงกันหรือเข้ากันได้กับ type ไม่เช่นนั้นจะได้ผลลัพธ์เป็น false
บรรทัดที่ 5-7 คือตัวอย่างวิธีใช้ตัวกระทำ is
หาก obj สามารถแปลงเป็น type ที่ตรงกันหรือเข้ากันได้กับ Person โค้ดบรรทัดที่ 6 จึงจะทำงาน
รูปที่ 2
type คือชื่อของ type ที่ต้องการตรวจสอบว่าตรงกันหรือเข้ากันได้กับ expr หรือไม่ ผลลัพธ์ที่ได้จากการทำงานจะเป็น true
ถ้า expr ไม่ใช่ค่า Null และ เป็น type ที่ตรงกันหรือเข้ากันได้กับ type ไม่เช่นนั้นจะได้ผลลัพธ์เป็น false
บรรทัดที่ 5-7 คือตัวอย่างวิธีใช้ตัวกระทำ is
หาก obj สามารถแปลงเป็น type ที่ตรงกันหรือเข้ากันได้กับ Person โค้ดบรรทัดที่ 6 จึงจะทำงาน
รูปที่ 2
รูปที่ 2 คือโค้ดทดสอบการใช้ตัวกระทำ is เพื่อตรวจสอบความเข้ากันของ type ที่เรานิยามขึ้นเอง 2 type คือ คลาส Class1 และ Class2
บรรทัด 9-17 คือ นิยามคลาส Class1 ที่สืบคุณสมบัติจาก interphase IFormatProvider ไม่ต้องสนใจ method GetFormat เพราะไม่ได้ใช้ในตัวอย่างนี้ แต่ต้องใส่implementไว้เพราะถูกบังคับโดยอินเตอร์เฟส IFormatProvider ไม่เช่นนั้นจะerror
บรรทัด 18-20 คือนิยามคลาส Class2 ที่สืบคุณสมบัติจาก Class1 ภายในมีสมาชิกหนึ่งตัว คือ property Value ที่ไม่ได้ใช้ในตัวอย่างนี้
บรรทัดที่ 26-41 คือโค้ดที่จะทำหน้าที่ใช้ตัวกระทำ is เพื่อตรวจสอบประเมินค่าของtypeทั้งสองที่นิยามไว้
บรรทัด 9-17 คือ นิยามคลาส Class1 ที่สืบคุณสมบัติจาก interphase IFormatProvider ไม่ต้องสนใจ method GetFormat เพราะไม่ได้ใช้ในตัวอย่างนี้ แต่ต้องใส่implementไว้เพราะถูกบังคับโดยอินเตอร์เฟส IFormatProvider ไม่เช่นนั้นจะerror
บรรทัด 18-20 คือนิยามคลาส Class2 ที่สืบคุณสมบัติจาก Class1 ภายในมีสมาชิกหนึ่งตัว คือ property Value ที่ไม่ได้ใช้ในตัวอย่างนี้
บรรทัดที่ 26-41 คือโค้ดที่จะทำหน้าที่ใช้ตัวกระทำ is เพื่อตรวจสอบประเมินค่าของtypeทั้งสองที่นิยามไว้
- บรรทัด 26 สร้างออพเจ็กต์ cl1 จากคลาส Class1
- บรรทัด 27 ตรวจว่าตรงกับ อินเตอร์เฟส IFormatProvider หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 28 ตรวจว่าตรงกับ ออพเจ็กต์ หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 29 ตรวจว่าตรงกับ Class1 หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 30 ตรวจว่าตรงกับ Class2 หรือไม่ ผลลัพธ์คือไม่ตรง
- บรรทัด 31 ทำหน้าที่เว้นบรรทัด
- บรรทัด 33 สร้างออพเจ็กต์ cl2 จากคลาส Class2
- บรรทัด 34 ตรวจว่าตรงกับ อินเตอร์เฟส IFormatProvider หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 35 ตรวจว่าตรงกับ Class2 หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 36 ตรวจว่าตรงกับ Class1 หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 39 ประกาศตัวแปร cl แล้วกำหนดให้มีค่าอ้างอิงไปยังออพเจ็กต์ cl2
- บรรทัด 40 ตรวจว่าตรงกับ Class1 หรือไม่ ผลลัพธ์คือตรง
- บรรทัด 41 ตรวจว่าตรงกับ Class2 หรือไม่ ผลลัพธ์คือตรง
รูปที่ 3
ผลลัพธ์การทำงานเป็นอย่างที่เห็นในรูปที่ 3
รูปที่ 4
รูปที่ 4
การใช้ตัวกระทำ is กับค่าที่ไม่เปลี่ยน คือนิพจน์ที่จะให้ค่าเป็น true หรือ false เสมอจะมีผลให้เกิดเออเรอร์แบบ “เตือน” ตอนคอมไพล์โปรแกรม โดยในโปรแกรมวิสชวลสตูดิโอจะแสดงเออเรอร์แบบนี้เป็นเส้นหยักสีเขียวใต้บรรทัดคำสั่งที่มีปัญหา เออเรอ์ชนิดนี้ไม่ทำให้เกิดอุปสรรคในการทำงานเพราะยังคอมไพล์ผ่านและรันได้ปรกติ ในรูปที่ 4 จะเห็นว่ามีเออเรอร์แบบนี้เกิดขึ้นทุกแห่งที่ใช้ตัวกระทำ is โปรดสังเกตว่านิพจน์ is ที่แปลงไทป์แบบ int ไปเป็นชนิดข้อมูลแบบ long และแบบ double จะให้ผลลัพธ์เป็น false ตลอดเพราะการแปลงไทป์นี้เกิดจากตัวกระทำ implicit
การใช้ตัวกระทำ is กับ ค่าที่ไม่เปลี่ยน คือ นิพจน์ที่จะให้ค่าเป็น true หรือ false เสมอจะมีผลให้เกิด error แบบ “เตือน” ตอน complie โปรแกรม
โดยในโปรแกรม visual studio จะแสดง error แบบนี้เป็นเส้นหยักสีเขียวใต้บรรทัดคำสั่งที่มีปัญหา
error ชนิดนี้ไม่ทำให้เกิดอุปสรรคในการทำงานเพราะยัง complie ผ่านและ runได้ปรกติ
ในรูปที่ 4 จะเห็นว่ามี error แบบนี้เกิดขึ้นทุกแห่งที่ใช้ตัวกระทำ is
โปรดสังเกตว่านิพจน์ is ที่แปลง type แบบ int ไปเป็นชนิดข้อมูลแบบ long
และ แบบ double จะให้ผลลัพธ์เป็น false ตลอดเพราะการแปลง type นี้เกิดจากตัวกระทำ implicit
รูปที่ 5
การใช้ตัวกระทำ is กับ ค่าที่ไม่เปลี่ยน คือ นิพจน์ที่จะให้ค่าเป็น true หรือ false เสมอจะมีผลให้เกิด error แบบ “เตือน” ตอน complie โปรแกรม
โดยในโปรแกรม visual studio จะแสดง error แบบนี้เป็นเส้นหยักสีเขียวใต้บรรทัดคำสั่งที่มีปัญหา
error ชนิดนี้ไม่ทำให้เกิดอุปสรรคในการทำงานเพราะยัง complie ผ่านและ runได้ปรกติ
ในรูปที่ 4 จะเห็นว่ามี error แบบนี้เกิดขึ้นทุกแห่งที่ใช้ตัวกระทำ is
โปรดสังเกตว่านิพจน์ is ที่แปลง type แบบ int ไปเป็นชนิดข้อมูลแบบ long
และ แบบ double จะให้ผลลัพธ์เป็น false ตลอดเพราะการแปลง type นี้เกิดจากตัวกระทำ implicit
รูปที่ 5
นอกจากจะใช้ตัวกระทำ is ต่อตัวแปรแล้วยังใช้ต่อค่าส่งกลับจาก method ได้ (แต่ต้องเป็น method ธรรมดาไม่ใช่ lymda หรือ methodแบบ Anonymous)
รูปที่ 5 แสดงตัวอย่างการใช้ตัวกระทำ is กับ method Ceiling ที่อยู่ในคลาส Math
บรรทัด 9 ประกาศและกำหนดค่าให้ตัวแปรเป็นแบบ double
บรรทัด 10 คำสั่ง if มีนิพจน์booleanตรวจสอบว่าตัวแปร number1 มีชนิดข้อมูลเป็น double หรือไม่ ปรากฏว่าเป็น
ทำให้บรรทัด 11 ทำงานแต่บรรทัด 13 ไม่ทำงาน
บรรทัด 15 ประกาศและกำหนดค่าให้ตัวแปรเป็นแบบ decimal
บรรทัด 15 คำสั่ง if มีนิพจน์booleanตรวจสอบว่าตัวแปร number2 มีชนิดข้อมูลเป็น double หรือไม่ ปรากฏว่าไม่เป็น
ทำให้บรรทัด 17 ไม่งานแต่บรรทัด 19 ทำงาน
รูปที่ 6
รูปที่ 5 แสดงตัวอย่างการใช้ตัวกระทำ is กับ method Ceiling ที่อยู่ในคลาส Math
บรรทัด 9 ประกาศและกำหนดค่าให้ตัวแปรเป็นแบบ double
บรรทัด 10 คำสั่ง if มีนิพจน์booleanตรวจสอบว่าตัวแปร number1 มีชนิดข้อมูลเป็น double หรือไม่ ปรากฏว่าเป็น
ทำให้บรรทัด 11 ทำงานแต่บรรทัด 13 ไม่ทำงาน
บรรทัด 15 ประกาศและกำหนดค่าให้ตัวแปรเป็นแบบ decimal
บรรทัด 15 คำสั่ง if มีนิพจน์booleanตรวจสอบว่าตัวแปร number2 มีชนิดข้อมูลเป็น double หรือไม่ ปรากฏว่าไม่เป็น
ทำให้บรรทัด 17 ไม่งานแต่บรรทัด 19 ทำงาน
รูปที่ 6
ตัวอย่างโปรแกรมรูปที่ 6 โค้ดบรรทัด 15-18 คือ นิยาม method DiceSum
ทำหน้าที่หาค่าผลรวมของตัวแปรที่เป็นรายการค่าจำนวนเต็มที่มี typeเป็น generic แบบ IEnumerable
ซึ่งทำได้โดยเรีย กmethod Sum() อย่างที่เห็นในบรรทัดที่ 17
method นี้ จะทำงานได้ดีกับรายการธรรมดา เช่น ลิสต์ที่มีหน่วยข้อมูลเป็น int ล้วน ๆ
แต่ถ้าในกรณีที่หน่วยข้อมูลบางอันเป็นลิสต์ด้วย (คือมีสภาพเป็นลิสต์ซ้อนลิสต์) การเรียก method Sum() จะไม่ได้ค่ารวมของหน่วยในลิสต์ที่ซ้อนอยู่
วิธีแก้ไข คือ เขียนนิยาม method DiceSum2 อย่างที่เห็นในบรรทัด 20-31 ที่จะวนค่าในตัวแปร values มาดู
ถ้าพบว่าเป็น IEnumerable ก็จะทำ Recursive
บรรทัด 23 ใช้คำสั่ง foreach เพื่อวนค่าของตัวแปร values
บรรทัด 25 ตรวจสอบว่าเป็นตัวเลขจำนวนเต็มหรือไม่ ถ้าใช่ให้เพิ่มค่า sum ด้วย
บรรทัดที่ 26 ถ้าไม่ใช่ บรรทัดที่ 27 จะตรวจสอบว่าเป็น type IEnumerable หรือไม่
ถ้าพบว่าใช่ บรรทัด 28 จะทำงานเพื่อเรียกตัวเองวนค่าใน IEnumerable ตัวที่ซ้อนอยู่ภายใน
ขอให้สังเกตว่านิพจน์ is บรรทัดที่ 27 ประกาศตัวแปรใหม่เพื่อนำไปใช้ในบรรทัดที่ 28 ได้ด้วย
นี่คือคุณสมบัติใหม่มีมาใน C# 7.0
รูปที่ 7
ทำหน้าที่หาค่าผลรวมของตัวแปรที่เป็นรายการค่าจำนวนเต็มที่มี typeเป็น generic แบบ IEnumerable
ซึ่งทำได้โดยเรีย กmethod Sum() อย่างที่เห็นในบรรทัดที่ 17
method นี้ จะทำงานได้ดีกับรายการธรรมดา เช่น ลิสต์ที่มีหน่วยข้อมูลเป็น int ล้วน ๆ
แต่ถ้าในกรณีที่หน่วยข้อมูลบางอันเป็นลิสต์ด้วย (คือมีสภาพเป็นลิสต์ซ้อนลิสต์) การเรียก method Sum() จะไม่ได้ค่ารวมของหน่วยในลิสต์ที่ซ้อนอยู่
วิธีแก้ไข คือ เขียนนิยาม method DiceSum2 อย่างที่เห็นในบรรทัด 20-31 ที่จะวนค่าในตัวแปร values มาดู
ถ้าพบว่าเป็น IEnumerable ก็จะทำ Recursive
บรรทัด 23 ใช้คำสั่ง foreach เพื่อวนค่าของตัวแปร values
บรรทัด 25 ตรวจสอบว่าเป็นตัวเลขจำนวนเต็มหรือไม่ ถ้าใช่ให้เพิ่มค่า sum ด้วย
บรรทัดที่ 26 ถ้าไม่ใช่ บรรทัดที่ 27 จะตรวจสอบว่าเป็น type IEnumerable หรือไม่
ถ้าพบว่าใช่ บรรทัด 28 จะทำงานเพื่อเรียกตัวเองวนค่าใน IEnumerable ตัวที่ซ้อนอยู่ภายใน
ขอให้สังเกตว่านิพจน์ is บรรทัดที่ 27 ประกาศตัวแปรใหม่เพื่อนำไปใช้ในบรรทัดที่ 28 ได้ด้วย
นี่คือคุณสมบัติใหม่มีมาใน C# 7.0
รูปที่ 7
คุณสมบัติใหม่ในคำสั่ง switch
การตรวจสอบด้วยคำสั่ง if และคำสั่ง else if จะไม่ดีหากมีเงื่อนไขจำนวนมาก เพราะโค้ดจะรกไม่เป็นระเบียบ
วิธีแก้ คือ ใช้คำสั่ง switch ที่สะดวกมาก
เพราะคำสั่ง case ใน C# 7.0 สนับสนุนการตรวจสอบลักษณะนี้ โดยไม่ต้องใช้นิพจน์ is
รูปที่ 7 คือโค้ดตัวอย่างการใช้คำสั่ง switch / case ที่มีคุณสมบัติแบบใหม่ดังกล่าว
บรรทัด 15-31 คือ method DiceSum3 ซึ่งมีการทำงานเหมือนตัวอย่างก่อนหน้านี้ (method DiceSum2) ต่างกันที่ DiceSum2 ใช้คำสั่ง if และ คำสั่ง else if
ขณะที่ DiceSum3 ใช้คำสั่ง switch / case กับคุณสมบัติแบบใหม่
โปรดสังเกตบรรทัด 22 คำสั่ง case ตรวจสอบชนิดข้อมูลของตัวแปร item ว่าเป็น int หรือไม่
และในขณะเดียวกันก็ประกาศตัวแปรใหม่คือ val เพื่อเอาไว้ใช้งานในบรรทัดถัดไปที่เป็นส่วนไส้ของ case นี้ด้วย
และในทำนองเดียวกันบรรทัด 25 คำสั่ง case ตรวจสอบชนิดข้อมูลของตัวแปร item ว่าเป็น IEnumerable<object> หรือไม่
และในขณะเดียวกันก็ประกาศตัวแปรใหม่คือ subList เพื่อเอาไว้ในงานในบรรทัดถัดไปที่เป็นส่วนไส้ของ case นี้ด้วยเช่นกัน
รูปที่ 8
วิธีแก้ คือ ใช้คำสั่ง switch ที่สะดวกมาก
เพราะคำสั่ง case ใน C# 7.0 สนับสนุนการตรวจสอบลักษณะนี้ โดยไม่ต้องใช้นิพจน์ is
รูปที่ 7 คือโค้ดตัวอย่างการใช้คำสั่ง switch / case ที่มีคุณสมบัติแบบใหม่ดังกล่าว
บรรทัด 15-31 คือ method DiceSum3 ซึ่งมีการทำงานเหมือนตัวอย่างก่อนหน้านี้ (method DiceSum2) ต่างกันที่ DiceSum2 ใช้คำสั่ง if และ คำสั่ง else if
ขณะที่ DiceSum3 ใช้คำสั่ง switch / case กับคุณสมบัติแบบใหม่
โปรดสังเกตบรรทัด 22 คำสั่ง case ตรวจสอบชนิดข้อมูลของตัวแปร item ว่าเป็น int หรือไม่
และในขณะเดียวกันก็ประกาศตัวแปรใหม่คือ val เพื่อเอาไว้ใช้งานในบรรทัดถัดไปที่เป็นส่วนไส้ของ case นี้ด้วย
และในทำนองเดียวกันบรรทัด 25 คำสั่ง case ตรวจสอบชนิดข้อมูลของตัวแปร item ว่าเป็น IEnumerable<object> หรือไม่
และในขณะเดียวกันก็ประกาศตัวแปรใหม่คือ subList เพื่อเอาไว้ในงานในบรรทัดถัดไปที่เป็นส่วนไส้ของ case นี้ด้วยเช่นกัน
รูปที่ 8
การตรวจสอบรูปแบบด้วยคำสั่ง switch สนับสนุนการใช้ตัวคงค่าด้วยซึ่งประหยัดเวลาเพราะช่วยตัดกรณีง่าย ๆ ออกไป
ยกตัวอย่างเช่นในรูปที่ 8
โค้ดบรรทัดที่ 38 เพิ่มกรณีเป็น 0 และบรรทัด 48 กรณีเป็น null นั่นคือไม่มีข้อมูลi nput
ตัวอย่างโค้ดนี้ยังแสดงให้เห็นว่า switch แบบใหม่นี้ลำดับของ case มีผลต่อการทำงานของโปรแกรม
นั่นคือ case ในบรรทัด 38 จะต้องอยู่ก่อนหน้า case ในบรรทัดที่ 40
มิฉะนั้นการตรวจสอบรูปแบบจะพบ int ก่อนแม้ว่าค่าของมันจะเป็น 0 ก็ตาม
ถ้าเราใส่ case ซ้ำกับเงื่อนไขที่ตรวจสอบไปแล้วตัวแปลภาษาจะแจ้ง error
ส่วน default ในบรรทัดที่ 50 จะทำงานหลังสุดแม้เราจะย้ายไปไว้ก่อนหน้า case อื่น ๆ
รูปที่ 9
ยกตัวอย่างเช่นในรูปที่ 8
โค้ดบรรทัดที่ 38 เพิ่มกรณีเป็น 0 และบรรทัด 48 กรณีเป็น null นั่นคือไม่มีข้อมูลi nput
ตัวอย่างโค้ดนี้ยังแสดงให้เห็นว่า switch แบบใหม่นี้ลำดับของ case มีผลต่อการทำงานของโปรแกรม
นั่นคือ case ในบรรทัด 38 จะต้องอยู่ก่อนหน้า case ในบรรทัดที่ 40
มิฉะนั้นการตรวจสอบรูปแบบจะพบ int ก่อนแม้ว่าค่าของมันจะเป็น 0 ก็ตาม
ถ้าเราใส่ case ซ้ำกับเงื่อนไขที่ตรวจสอบไปแล้วตัวแปลภาษาจะแจ้ง error
ส่วน default ในบรรทัดที่ 50 จะทำงานหลังสุดแม้เราจะย้ายไปไว้ก่อนหน้า case อื่น ๆ
รูปที่ 9
ตัวอย่างโค้ดที่ผ่านทั้งหมดมาแสดงการตรวจสอบรูปแบบของแต้มของลูกเต๋าธรรมดา
รูปที่ 9 เพิ่มโครงสร้างข้อมูลแบบ Struct เพื่อนิยามลูกเต๋าแบบสิบหน้า
ลูกเต๋าชนิดนี้จะให้ค่า 0 ถึง 9 ถ้าใช้สองลูกจะได้ค่าจาก 00 ถึง 99
รูปที่ 10
รูปที่ 9 เพิ่มโครงสร้างข้อมูลแบบ Struct เพื่อนิยามลูกเต๋าแบบสิบหน้า
ลูกเต๋าชนิดนี้จะให้ค่า 0 ถึง 9 ถ้าใช้สองลูกจะได้ค่าจาก 00 ถึง 99
รูปที่ 10
รูปที่ 10 แสดงตัวอย่างโค้ดการตรวจสอบรูปแบบด้วยคำสั่ง switch ที่เพิ่มกรณีลูกเต๋าสิบหน้า (ดูบรรทัด 79)
จะเห็นว่าเราตรวจสอบว่าเป็นลูกเต๋าแบบสิบหน้าหรือไม่
ในขณะเดียวกันก็สร้าง Object ไต์ลูกเต๋าสิบหน้าขึ้นเพื่อนำไปใช้ในบรรทัด 80 ด้วย
เหล่านี้คือคุณสมบัติใหม่ของคำสั่ง switch ที่ช่วยให้การเขียนโค้ดเพื่อตรวจสอบรูปแบบทำได้สะดวกมาก
เพราะสามารถตรวจสอบชนิดข้อมูลของ object และกระทำต่อ object ได้ง่ายกว่าเดิม
รูปที่ 11
จะเห็นว่าเราตรวจสอบว่าเป็นลูกเต๋าแบบสิบหน้าหรือไม่
ในขณะเดียวกันก็สร้าง Object ไต์ลูกเต๋าสิบหน้าขึ้นเพื่อนำไปใช้ในบรรทัด 80 ด้วย
เหล่านี้คือคุณสมบัติใหม่ของคำสั่ง switch ที่ช่วยให้การเขียนโค้ดเพื่อตรวจสอบรูปแบบทำได้สะดวกมาก
เพราะสามารถตรวจสอบชนิดข้อมูลของ object และกระทำต่อ object ได้ง่ายกว่าเดิม
รูปที่ 11
รูปที่ 11 คือ method Find ทำหน้าที่วนค่าใน metrix เพื่อหาข้อมูลตำแหน่งที่ต้องการ
เมื่อพบแล้วส่งค่าให้แก่ฟังก์ชัน predicate เพื่อประมวลผล ตอนจบส่งค่าหน่วยของเมทริกซ์ที่ถูกประมวลผลกลับไปให้โค้ดที่เรียก
มีประเด็นที่เป็นข้อจำกัดหลายอย่างเกี่ยวกับโค้ดตัวอย่างนี้
ประเด็นแรกคือมันเป็นเ method แบบ public ที่ส่งค่ากลับเป็น tuple ซึ่งภาษา C# สนับสนุนทั้งสองอย่างโดยไม่มีปัญหา
แต่ชนิดข้อมูลที่จะนำมาใช้ด้วยกันได้ต้องเป็นคลาสหรือ structure ที่ผู้ใช้นิยามเอง
อีกประเด็นหนึ่งคือ method นี้ส่งค่ากลับเป็นค่าดรรชนีของ metrix ซึ่งเป็นค่าคู่
โค้ดส่วนที่จะเรียก method นี้จะต้องใช้ค่าส่งกลับนั้นเป็นตัวเข้าถึงค่านั้นใน metrix เพื่อเปลี่ยนแปลงมันอีกต่อหนึ่ง
รูปที่ 12
เมื่อพบแล้วส่งค่าให้แก่ฟังก์ชัน predicate เพื่อประมวลผล ตอนจบส่งค่าหน่วยของเมทริกซ์ที่ถูกประมวลผลกลับไปให้โค้ดที่เรียก
มีประเด็นที่เป็นข้อจำกัดหลายอย่างเกี่ยวกับโค้ดตัวอย่างนี้
ประเด็นแรกคือมันเป็นเ method แบบ public ที่ส่งค่ากลับเป็น tuple ซึ่งภาษา C# สนับสนุนทั้งสองอย่างโดยไม่มีปัญหา
แต่ชนิดข้อมูลที่จะนำมาใช้ด้วยกันได้ต้องเป็นคลาสหรือ structure ที่ผู้ใช้นิยามเอง
อีกประเด็นหนึ่งคือ method นี้ส่งค่ากลับเป็นค่าดรรชนีของ metrix ซึ่งเป็นค่าคู่
โค้ดส่วนที่จะเรียก method นี้จะต้องใช้ค่าส่งกลับนั้นเป็นตัวเข้าถึงค่านั้นใน metrix เพื่อเปลี่ยนแปลงมันอีกต่อหนึ่ง
รูปที่ 12
รูปที่ 12 คือโค้ดส่วนที่เรียกใช้ method Find
โค้ดบรรทัด 4 เรียกฟังก์ชัน Find สิ่งที่ส่งไปเป็น argument คือค่าอ้างอิงไปยัง metrix และ lambda
ค่าที่ได้รับกลับมาจาก method Find จะถูกเก็บไว้ในตัวแปร indices ซึ่งเป็น tuple
บรรทัด 6 ค่าจาก tuple ถูกนำมาใช้เป็นตัวอ้างอิงหน่วยข้อมูลใน metrix
รูปที่ 13
โค้ดบรรทัด 4 เรียกฟังก์ชัน Find สิ่งที่ส่งไปเป็น argument คือค่าอ้างอิงไปยัง metrix และ lambda
ค่าที่ได้รับกลับมาจาก method Find จะถูกเก็บไว้ในตัวแปร indices ซึ่งเป็น tuple
บรรทัด 6 ค่าจาก tuple ถูกนำมาใช้เป็นตัวอ้างอิงหน่วยข้อมูลใน metrix
รูปที่ 13
เพื่อแก้ปัญหาหรือคือข้อจำกัดต่าง ๆ ดังกล่าวของ method ในรูป 12
เราควรใช้วิธีให้ method ส่งค่ากลับมาเป็นค่าอ้างอิงไปยังหน่วยใน metrixโดยตรง
ซึ่งทำได้โดยกำหนดให้ค่าส่งกลับเป็น pointer ที่ชี้ไปยัง int ในตัวอย่างก่อนหน้านี้
และต้องเขียนโดยใช้ unsafe ที่อาจไม่เหมาะ
อีกวิธีหนึ่งคือให้ส่งค่ากลับเป็นแบบ ref ตามตัวอย่างโค้ดในรูปที่ 13
โปรดสังเกตบรรทัด 25 ตรงที่เป็นส่วนกำหนดค่าส่งกลับมีคำสั่ง ref เพื่อกำหนดว่าส่งกลับเป็นตัวชี้ไปยังตำแหน่งของข้อมูล
แต่ปัญหาของโค้ดนี้คือบรรทัดที่ 30 คำสั่ง return ส่งค่าที่เป็น value typeกลับไป (ไม่ใช่ reference type)
ตัวแปลภาษาจะพบความผิดปรกตินี้และจะไม่ complie โปรแกรม
ภาษา C# 7.0 มีวิธีแก้ปัญหานี้ดังมีรายละเอียดตามที่จะนำเสนอในตอนต่อไป
เราควรใช้วิธีให้ method ส่งค่ากลับมาเป็นค่าอ้างอิงไปยังหน่วยใน metrixโดยตรง
ซึ่งทำได้โดยกำหนดให้ค่าส่งกลับเป็น pointer ที่ชี้ไปยัง int ในตัวอย่างก่อนหน้านี้
และต้องเขียนโดยใช้ unsafe ที่อาจไม่เหมาะ
อีกวิธีหนึ่งคือให้ส่งค่ากลับเป็นแบบ ref ตามตัวอย่างโค้ดในรูปที่ 13
โปรดสังเกตบรรทัด 25 ตรงที่เป็นส่วนกำหนดค่าส่งกลับมีคำสั่ง ref เพื่อกำหนดว่าส่งกลับเป็นตัวชี้ไปยังตำแหน่งของข้อมูล
แต่ปัญหาของโค้ดนี้คือบรรทัดที่ 30 คำสั่ง return ส่งค่าที่เป็น value typeกลับไป (ไม่ใช่ reference type)
ตัวแปลภาษาจะพบความผิดปรกตินี้และจะไม่ complie โปรแกรม
ภาษา C# 7.0 มีวิธีแก้ปัญหานี้ดังมีรายละเอียดตามที่จะนำเสนอในตอนต่อไป