การใช้งานจริงสำหรับคำหลัก“ ภายใน” ใน C #


420

คุณช่วยอธิบายการใช้งานจริงสำหรับinternalคำหลักใน C # ได้ไหม?

ฉันรู้ว่าinternalตัวดัดแปลง จำกัด การเข้าถึงแอสเซมบลีปัจจุบัน แต่เมื่อใดและในสถานการณ์ใดที่ฉันควรใช้

คำตอบ:


379

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

จากMSDN (ผ่าน archive.org):

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

คุณยังสามารถใช้ตัวแก้ไขภายในพร้อมกับInternalsVisibleToแอตทริบิวต์ระดับแอสเซมบลีเพื่อสร้างแอสเซมบลี "เพื่อน" ที่ได้รับการเข้าถึงพิเศษไปยังคลาสภายในแอสเซมบลีเป้าหมาย

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


8
แอตทริบิวต์ InternalsVisibleTo เป็นความช่วยเหลือที่ดี ขอบคุณ.
ลบ

33
ความรู้สึกของฉันคือตั้งแต่วินาทีที่คุณต้องการภายในมีบางอย่างผิดปกติในการออกแบบที่ไหนสักแห่ง IMHO เราควรใช้ OO บริสุทธิ์เพื่อแก้ปัญหาทั้งหมด ในขณะนี้ฉันกำลังเฝ้าดูการใช้ภายในหนึ่งล้านครั้งในแหล่ง. NET Framework ยกเว้นวิธีการใช้ประโยชน์จากสิ่งที่พวกเขาใช้เอง ผ่านการใช้งานภายในพวกเขาสร้างเสาหินขนาดใหญ่ที่เป็นโมดุลแบบแยกส่วน แต่จะพังทลายลงเมื่อคุณพยายามแยกแยะสิ่งต่าง ๆ นอกจากนี้ความปลอดภัยไม่ใช่ข้อโต้แย้งเนื่องจากมีภาพสะท้อนต่อการช่วยเหลือ
หน้าตาบูดบึ้งของ Despair

26
@GrimaceofDespair: ให้ฉันเพิ่มความคิดเห็นที่ diagreeing ที่นี่ ฉันเองเห็นว่าภายในเป็นเวอร์ชั่นที่มีประโยชน์มากของตัวดัดแปลง "สาธารณะ" ในโซลูชันหลายโครงการขนาดใหญ่ การเพิ่มโมดิฟายเออร์นี้ในคลาสในโครงการย่อยของฉันห้าม "การใช้แบบสุ่ม" ของคลาสนี้โดยโปรเจ็กต์ย่อยอื่นในโซลูชันและทำให้เป็นไปได้ที่ฉันจะบังคับให้ใช้ไลบรารีของฉันอย่างเหมาะสม ถ้าฉันจะต้องทำการปรับเปลี่ยนบางอย่างในภายหลังฉันจะไม่ต้องถามตัวเองว่า "รอ แต่ทำไมคนนั้นถึงไปและสร้างอินสแตนซ์ของคลาสพอยต์ซึ่งฉันต้องการเพื่อจุดประสงค์ของตัวเองในการคำนวณนี้เท่านั้น"?
KT

3
หากจะกล่าวอีกนัยหนึ่งหากทุกคนจะพึ่งพาการใช้งานภายในของ SmtpClient และในช่วงเวลาหนึ่งที่มีการค้นพบข้อผิดพลาดที่นั่น. NET จะมีปัญหาร้ายแรงในการแก้ไขข้อผิดพลาดนั้นหรืออาจทำให้เป็นเวลานาน ฉันจำได้ว่าฉันอ่านบทความที่น่าขบขันครั้งหนึ่งซึ่งอธิบายถึงความยาวที่นักพัฒนา Windows ต้องดำเนินการเพื่อให้ "ความเข้ากันได้ของบั๊ก" กับโปรแกรมเก่าทั้งหมดที่ใช้คุณสมบัติและข้อบกพร่องภายในต่างๆ การทำซ้ำข้อผิดพลาดนี้ด้วย. NET ไม่ได้มีความหมาย
KT

13
ฉันคิดว่าภายในเป็นวิธีที่มีประโยชน์มากกว่าสาธารณะ ครั้งเดียวที่คุณใช้สาธารณะคือเมื่อคุณพูดอย่างชัดเจนว่า "ที่นี่ผู้ใช้ - ฉันจะจัดหาฟังก์ชันที่มีประโยชน์ให้คุณใช้" หากคุณกำลังเขียนแอปพลิเคชันแทนที่จะเป็นห้องสมุดผู้ใช้ทุกอย่างควรอยู่ภายในเพราะคุณไม่ได้พยายามให้ฟังก์ชั่นการโทรจากภายนอก หากคุณกำลังเขียนไลบรารีผู้ใช้เฉพาะฟังก์ชั่นที่มีประโยชน์ที่คุณคาดหวังที่จะมอบให้กับผู้ใช้บำรุงรักษาสนับสนุนและเก็บจนถึงเวลาสิ้นสุดควรเป็นแบบสาธารณะ มิฉะนั้นทำให้เป็นภายใน
Darrell Plank

85

หาก Bob ต้องการ BigImportantClass จากนั้น Bob ต้องรับคนที่เป็นเจ้าของโครงการ A เพื่อลงทะเบียนเพื่อรับประกันว่า BigImportantClass จะถูกเขียนขึ้นเพื่อตอบสนองความต้องการของเขาทดสอบเพื่อให้แน่ใจว่าตรงกับความต้องการของเขาถูกจัดทำเป็นเอกสารตามความต้องการของเขาและกระบวนการ จะถูกวางไว้เพื่อให้แน่ใจว่ามันจะไม่เปลี่ยนแปลงเพื่อที่จะไม่ตอบสนองความต้องการของเขาอีกต่อไป

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

จุดภายในไม่ได้ทำให้ชีวิตยากสำหรับบ๊อบ มันช่วยให้คุณสามารถควบคุมสิ่งที่สัญญาว่าจะให้โครงการ A ราคาแพงเกี่ยวกับคุณสมบัติอายุการใช้งานความเข้ากันได้และอื่น ๆ


5
ทำให้รู้สึกที่สมบูรณ์แบบ เพียงแค่ต้องการให้เรามีความสามารถในการแทนที่สมาชิกภายในเพราะเราทุกคนยินยอมผู้ใหญ่ที่นี่
cwallenpoole

6
@EricLippert ไม่ใช่สิ่งที่ฉันต้องการ ถ้าฉันรับรหัสที่รวบรวมซึ่งมี "ภายใน" อยู่ในนั้นฉันติดอยู่ใช่ไหม ไม่มีทางที่จะบอกคอมไพเลอร์ว่า "ไม่ผู้พัฒนารายอื่นโกหกคุณคุณควรเชื่อใจฉันแทน" เว้นแต่ฉันจะใช้การสะท้อนกลับ
cwallenpoole

11
@cwallenpoole: หากคุณใช้รหัสที่เขียนโดยคนโกหกผู้เขียนโค้ดที่คุณไม่ชอบให้หยุดใช้รหัสของพวกเขาและเขียนรหัสของคุณเองที่คุณชอบดีกว่า
Eric Lippert

2
@EricLippert ที่ควรจะเป็นลิ้นในแก้มฉันไม่ได้ตั้งใจที่จะรุกราน (ส่วนใหญ่ฉันแค่พยายามยืนยันว่าฉันเป็น SOL ในกรณีเช่นนี้)
cwallenpoole

5
@cwallenpoole: ฉันไม่ได้โกรธน้อย ฉันเสนอคำแนะนำที่ดีหากคุณพบว่าตัวเองติดอยู่ในสถานการณ์ที่โชคร้าย
Eric Lippert

60

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


4
PFF การดู bytecode ด้วย disassembler จะยังคงทำให้ชัดเจนว่าโค้ดทำงานอย่างไร ผู้สังเกตการณ์แทบจะไม่ยับยั้งใครเลยที่พยายามจะเข้าไปภายใน ไม่เคยได้ยินชื่อแฮ็กเกอร์ที่หยุดเพียงเพราะเขาไม่ได้รับชื่อฟังก์ชั่นที่มีประโยชน์
Nyerguds

28
ดังนั้นคุณจะไม่ล็อคประตูของคุณเมื่อคุณนอนหลับเพราะคุณไม่เคยได้ยินเรื่องขโมยมาโดยล็อค?
Sergio

4
นั่นเป็นเหตุผลที่ฉันช่วงชิงคลาสและชื่อตัวแปรในซอร์สโค้ด คุณอาจจะคิดได้ว่า PumpStateComparator คืออะไร แต่คุณสามารถเดาได้ว่า LpWj4mWE คืออะไร? #jobsecurity (ฉันไม่ได้ทำสิ่งนี้และโปรดอย่าทำสิ่งนี้กับผู้คนทางอินเทอร์เน็ต)
Slothario

32

หากคุณกำลังเขียน DLL ที่รวมเอาฟังก์ชันการทำงานที่ซับซ้อนจำนวนหนึ่งไว้ใน API สาธารณะอย่างง่ายระบบจะใช้“ ภายใน” กับสมาชิกคลาสซึ่งไม่ควรเปิดเผยต่อสาธารณะ

การซ่อนความซับซ้อน (aka encapsulation) เป็นแนวคิดหลักของวิศวกรรมซอฟต์แวร์ที่มีคุณภาพ


20

คำหลักภายในถูกใช้อย่างมากเมื่อคุณสร้าง wrapper ผ่านโค้ดที่ไม่มีการจัดการ

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

คุณสามารถดู Mono.Cairo มันเป็นเสื้อคลุมรอบ ๆ cairo ไลบรารี่ที่ใช้วิธีนี้


12

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

เนื่องจากอินเทอร์เฟซแอสเซมบลีมักแคบกว่าผลรวมของอินเทอร์เฟซของคลาสมีหลาย ๆ ที่ที่ฉันใช้


3
หากคุณ "ใช้เป็นตัวดัดแปลงที่เข้มงวดเท่าที่จะทำได้" ทำไมไม่เป็นส่วนตัวล่ะ
R. Martinho Fernandes

6
เนื่องจากไพรเวตเข้มงวดเกินไปเมื่อต้องเข้าถึงคุณสมบัติ / เมธอดนอกคลาสและกรณีเมื่อต้องเข้าถึงจาก asse อื่นจึงไม่บ่อยนัก
Ilya Komakhin

11

ฉันพบว่าภายในนั้นมีการใช้มากเกินไป คุณไม่ควรเปิดเผยฟังก์ชั่นบางอย่างต่อคลาสที่คุณไม่ต้องการให้กับผู้บริโภครายอื่น

ในความคิดของฉันแบ่งอินเทอร์เฟซการแบ่งสิ่งที่เป็นนามธรรม นี่ไม่ได้เป็นการบอกว่าไม่ควรใช้ แต่วิธีที่ดีกว่าคือการปรับโครงสร้างให้เป็นคลาสที่แตกต่างหรือใช้ในวิธีที่ต่างกันถ้าเป็นไปได้ อย่างไรก็ตามสิ่งนี้อาจไม่สามารถทำได้เสมอไป

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

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

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


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

8

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

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

namespace Base.Assembly
{
  ชั้นนามธรรมสาธารณะ
  {
    โมฆะนามธรรมภายในเป็นโมฆะ SomeMethod ();
  }

  // มันใช้งานได้ดีเพราะมันอยู่ในชุดประกอบเดียวกัน
  ChildWithin คลาสพับลิก: พาเรนต์
  {
    การแทนที่ภายในเป็นโมฆะ SomeMethod ()
    {
    }
  }
}

namespace Another.Assembly
{
  // Kaboom เพราะคุณไม่สามารถแทนที่วิธีการภายใน
  คลาส ChildOutside สาธารณะ: ผู้ปกครอง
  {
  }

  การทดสอบระดับสาธารณะ 
  { 

    // สบายดี
    ผู้ปกครองส่วนตัว _parent;

    การทดสอบสาธารณะ ()
    {
      // ยังไม่เป็นไร
      _parent = new ChildWithin ();
    }
  }
}

อย่างที่คุณเห็นมันช่วยให้บางคนสามารถใช้คลาส Parent ได้อย่างมีประสิทธิภาพโดยไม่สามารถสืบทอดได้


7

ตัวอย่างนี้มีสองไฟล์: Assembly1.cs และ Assembly2.cs ไฟล์แรกมีคลาสฐานภายในคือ BaseClass ในไฟล์ที่สองความพยายามในการสร้างอินสแตนซ์ BaseClass จะทำให้เกิดข้อผิดพลาด

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

ในตัวอย่างนี้ใช้ไฟล์เดียวกับที่คุณใช้ในตัวอย่างที่ 1 และเปลี่ยนระดับการเข้าถึงของ BaseClass เพื่อประชาชน นอกจากนี้ยังเปลี่ยนระดับการเข้าถึงของสมาชิก IntM ไปภายใน ในกรณีนี้คุณสามารถยกตัวอย่างคลาสได้ แต่คุณไม่สามารถเข้าถึงสมาชิกภายในได้

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

แหล่งที่มา : http://msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx


6

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

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


6

การใช้งานภายในที่น่าสนใจมาก - โดยที่สมาชิกภายในของหลักสูตรจะถูก จำกัด เฉพาะในแอสเซมบลีที่ได้รับการประกาศเท่านั้น - กำลังรับฟังก์ชั่น "เพื่อน" ในระดับหนึ่ง สมาชิกเพื่อนเป็นสิ่งที่มองเห็นได้เฉพาะกับแอสเซมบลีอื่นบางอย่างภายนอกแอสเซมบลีที่ประกาศ C # ไม่มีการสนับสนุนสำหรับเพื่อน แต่ CLR ทำ

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

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


5

กฎของหัวแม่มือมีสมาชิกสองประเภท:

  • พื้นผิวสาธารณะ : มองเห็นได้จากแอสเซมบลีภายนอก (สาธารณะป้องกันและป้องกันภายใน): ผู้เรียกไม่น่าเชื่อถือดังนั้นการตรวจสอบพารามิเตอร์เอกสารประกอบวิธีการ ฯลฯ
  • พื้นผิวส่วนตัว : ไม่สามารถมองเห็นได้จากแอสเซมบลีภายนอก (คลาสส่วนตัวและภายในหรือภายใน): ผู้เรียกมักเชื่อถือได้ดังนั้นการตรวจสอบความถูกต้องของพารามิเตอร์เอกสารวิธีการ ฯลฯ อาจถูกมองข้าม

4

การลดเสียงรบกวนยิ่งคุณใช้ห้องสมุดน้อยลง การพิสูจน์อักษรการงัดแงะ / ความปลอดภัยเป็นอีกหนึ่ง (แม้ว่า Reflection สามารถเอาชนะได้)


4

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

นอกจากนี้หากมีข้อผิดพลาดในการประกอบของคุณมีโอกาสน้อยที่การแก้ไขที่แนะนำการเปลี่ยนแปลงที่ทำลาย หากไม่มีคลาสภายในคุณจะต้องสมมติว่าการเปลี่ยนสมาชิกสาธารณะของคลาสใด ๆ จะเป็นการเปลี่ยนแปลงที่ไม่สิ้นสุด ด้วยคลาสภายในคุณสามารถสันนิษฐานได้ว่าการแก้ไขสมาชิกสาธารณะจะแบ่งเฉพาะ API ภายในของแอสเซมบลีเท่านั้น (และแอสเซมบลีใด ๆ ที่อ้างอิงในแอตทริบิวต์ InternalsVisibleTo)

ฉันชอบการห่อหุ้มที่ระดับชั้นเรียนและในระดับการชุมนุม มีบางคนที่ไม่เห็นด้วยกับสิ่งนี้ แต่ก็ยินดีที่ได้ทราบว่ามีฟังก์ชั่นให้ใช้งาน


2

ฉันมีโครงการที่ใช้ LINQ-to-SQL สำหรับ data back-end ฉันมีเนมสเปซหลักสองรายการ: Biz และ Data รูปแบบข้อมูล LINQ อาศัยอยู่ในข้อมูลและมีการทำเครื่องหมาย "ภายใน"; Biz namespace มีคลาสสาธารณะซึ่งล้อมรอบคลาสข้อมูล LINQ

ดังนั้นมีData.ClientและBiz.Client; หลังเปิดเผยคุณสมบัติที่เกี่ยวข้องทั้งหมดของวัตถุข้อมูลเช่น:

private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }

วัตถุ Biz มีตัวสร้างส่วนตัว (เพื่อบังคับให้ใช้วิธีการจากโรงงาน) และตัวสร้างภายในซึ่งมีลักษณะดังนี้:

internal Client(Data.Client client) {
    this._client = client;
}

สามารถใช้คลาสธุรกิจใดก็ได้ในไลบรารี แต่ front-end (UI) ไม่มีวิธีเข้าถึงโมเดลข้อมูลโดยตรงเพื่อให้แน่ใจว่าเลเยอร์ธุรกิจทำหน้าที่เป็นตัวกลางเสมอ

นี่เป็นครั้งแรกที่ฉันใช้internalมันมากและพิสูจน์ได้ว่ามีประโยชน์มาก


2

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

อย่างไรก็ตามฉันไม่สามารถมองเห็นจุดใด ๆ ในการสร้างชั้นเรียนหรือสมาชิกinternalโดยไม่มีเหตุผลเฉพาะเพียงเล็กน้อยเท่าที่เหมาะสมที่จะทำให้พวกเขาpublicหรือprivateไม่มีเหตุผลที่เฉพาะเจาะจง



1

การใช้คำหลักภายในหนึ่งครั้งคือ จำกัด การเข้าถึงการใช้งานที่เป็นรูปธรรมจากผู้ใช้ชุดประกอบของคุณ

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

นอกจากนี้ตัวสร้างภายในช่วยให้คุณสามารถควบคุมสถานที่และเวลาที่คลาสสาธารณะเป็นอย่างอื่น


1

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

ยินดีต้อนรับความคิดเห็นเกี่ยวกับวิธีการนี้


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

1
@Howiecamp: ส่วนใหญ่เนื่องจาก IEnumerable ให้การเข้าถึงแบบอ่านอย่างเดียวในรายการโดยที่ราวกับว่าคุณเปิดเผยรายการโดยตรงลูกค้าสามารถแก้ไขได้ (เช่นองค์ประกอบลบเป็นต้น) ซึ่งอาจไม่ได้ตั้งใจ
Samik R

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

1

โปรดทราบว่าคลาสใด ๆ ที่กำหนดไว้publicจะปรากฏขึ้นโดยอัตโนมัติใน Intellisense เมื่อมีคนดูเนมสเปซโครงการของคุณ จากมุมมอง API เป็นสิ่งสำคัญที่จะแสดงเฉพาะผู้ใช้ในโครงการของคุณในชั้นเรียนที่สามารถใช้ ใช้internalคำหลักเพื่อซ่อนสิ่งที่ไม่ควรเห็น

หากคุณBig_Important_Classสำหรับโครงการ A มีไว้สำหรับใช้นอกโครงการของคุณคุณไม่ควรทำเครื่องหมายinternalโครงการมีวัตถุประสงค์สำหรับใช้ภายนอกโครงการของคุณแล้วคุณไม่ควรทำเครื่องหมาย

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


เหตุใดจึงไม่ใช้ส่วนตัวแทน
ZERO Prisoner

1
privateคำหลักเท่านั้นที่สามารถนำมาใช้ในการเรียนหรือ structs ที่ได้กำหนดไว้ในระดับอื่นหรือ struct คลาสที่กำหนดภายในเนมสเปซสามารถประกาศpublicหรือinternalเท่านั้น
Matt Davis

1

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

  1. มีแนวโน้มที่จะเปลี่ยนแปลงในรุ่นอนาคต (ถ้าเป็นสาธารณะคุณจะผิดรหัสลูกค้า)
  2. ไร้ประโยชน์กับลูกค้าและอาจทำให้เกิดความสับสน
  3. ไม่ปลอดภัย (การใช้งานที่ไม่เหมาะสมอาจทำให้ห้องสมุดของคุณไม่ดี)

เป็นต้น

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


-7

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

public class DangerousClass {
    public void SafeMethod() { }
    internal void UpdateGlobalStateInSomeBizarreWay() { }
}

คุณกำลังพยายามจะพูดว่าอะไร? มันไม่ชัดเจนมาก อย่างน้อยก็ไม่ใช่สำหรับฉัน
pqsk

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