เมื่อใดจึงเหมาะสมที่จะใช้คลาส C # บางส่วน


517

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


ดูเพิ่มเติมได้ที่นี่: softwareengineering.stackexchange.com/questions/71494/ …
RenniePet

คำตอบ:


423

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

วิธีที่ดีกว่าในการดูคือการดูว่านักออกแบบทำงานอย่างไรก่อนเรียนบางส่วน ผู้ออกแบบ WinForms จะคายรหัสทั้งหมดที่อยู่ในภูมิภาคด้วยความคิดเห็นที่พูดหนักแน่นเกี่ยวกับการไม่แก้ไขรหัส มันต้องแทรกฮิวริสติกทุกประเภทเพื่อค้นหารหัสที่สร้างขึ้นเพื่อการประมวลผลในภายหลัง ตอนนี้มันสามารถเปิดไฟล์ designer.cs และมีความมั่นใจในระดับสูงว่ามันมีเพียงรหัสที่เกี่ยวข้องกับนักออกแบบ


70
ล่อลวงเพื่อให้คุณ -1 ให้ฉันฝันร้ายเกี่ยวกับวิธีการสิ่งที่ไม่ดีอยู่ก่อนเรียนบางส่วน :)
จอน B

9
@ จอน :) ฉันคิดว่าเราทุกคนมีฝันร้ายเหล่านั้น
JaredPar

18
เมื่อฉันเขียนโปรแกรมสร้างโค้ดที่สร้างเส้นมากกว่า 36K ขึ้นไป (หรืออาจจะมากกว่านั้นฉันไม่จำได้เลย) และบรรณาธิการของฉันถูกบล็อกเมื่อเปิดแหล่งที่มา คลาสบางส่วนทำให้ฉันเห็นโค้ดที่ผลิตโดยไม่ต้องมี RAM ขนาด 4 GB
Luca

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

5
@Gordon - คำตอบของ HumerGu เป็นอีกสิ่งหนึ่งที่ฉันคิดว่าค่อนข้างยากที่จะโต้แย้ง ชั้นเรียนบางส่วนจะมีประโยชน์มากสำหรับการใช้อินเตอร์เฟซใน C # และทำให้สมาชิกในอินเตอร์เฟซได้อย่างชัดเจนแยกจากสมาชิกระดับ: stackoverflow.com/questions/3601901/why-use-partial-classes/...
STW

261

การใช้งานอื่นคือการแยกการใช้อินเทอร์เฟซต่าง ๆ เช่น:

partial class MyClass : IF1, IF2, IF3
{
    // main implementation of MyClass
}


partial class MyClass
{
    // implementation of IF1
}

partial class MyClass
{
    // implementation of IF2
}

6
จุดดี! มันเป็นสิ่งที่ฉันทำมาแล้วและลืมไปแล้ว แต่เป็นวิธีที่ดีในการทำให้สมาชิกส่วนต่อประสานมองเห็นได้ชัดเจน (โดยเฉพาะใน C # เนื่องจาก VB.NET ใช้Implementsคำหลักเพื่อแสดงว่าวิธีนั้นเป็นของส่วนต่อประสาน)
STW

2
จุดที่ดีมาก ๆ แต่ละอินเทอร์เฟซสามารถถูกนำไปใช้โดยนักพัฒนาและเป็นวิธีที่ดีในการค้นหาการใช้งานอินเทอร์เฟซได้อย่างง่ายดาย
kokabi

3
เราจะรู้ได้อย่างไรว่า IF1 นั้นเป็นอย่างไรสำหรับคำสั่งของการประกาศคลาส?
kuldeep

17
ใช้งานได้ดี แต่เป็นตัวอย่างที่ไม่ดี ทำไมโอเคทำไมคุณถึงกำหนดอินเทอร์เฟซทั้งหมดในคลาสย่อยบางส่วนและใช้อินเทอร์เฟซเดียวกันเหล่านั้นในคลาสบางส่วนอื่น ๆ ..
inkredibl

4
ฮ่าฉันเพิ่งค้นหาคำถามนี้เพื่อดูว่าการแยกการใช้งานอินเทอร์เฟซเป็นการใช้มาตรฐานสำหรับคลาสบางส่วนหรือไม่ ดีใจที่เห็นคนอื่นเห็นว่าเป็นความคิดที่ดี ฉันเห็นด้วยกับ @inkredibl เกี่ยวกับการใส่คำจำกัดความอินเทอร์เฟซพร้อมกับคลาสบางส่วนที่ใช้งาน
Kim

171

นอกเหนือจากคำตอบอื่น ๆ ...

ฉันพบว่าพวกเขามีประโยชน์ในฐานะก้าวย่างในการสร้างชั้นเรียนพระเจ้าอีกครั้ง หากคลาสมีความรับผิดชอบหลายอย่าง (โดยเฉพาะถ้าเป็นไฟล์โค้ดที่มีขนาดใหญ่มาก) ฉันพบว่ามันมีประโยชน์ในการเพิ่มคลาสบางส่วน 1x ต่อความรับผิดชอบเป็นพาสแรกสำหรับการจัดระเบียบและจากนั้นทำการเปลี่ยนรหัสใหม่

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

อย่างไรก็ตาม - เพื่อความชัดเจน - นี่คือรหัสที่ไม่ดีในตอนท้ายของการพัฒนาคุณยังต้องการความรับผิดชอบหนึ่งอย่างต่อหนึ่งคลาส ( ไม่ใช่ต่อบางส่วนของคลาส) มันเป็นเพียงก้าวย่างเท่านั้น :)


23
ดีมาก: "... ในตอนท้ายของการพัฒนาคุณยังต้องการความรับผิดชอบหนึ่งอย่างต่อคลาส ( ไม่ใช่ต่อบางส่วน) ... "
kokabi

สำหรับฉันมันไม่ใช่สไตล์การเขียนโค้ดที่ดี แต่สามารถทำให้โค้ดที่ไม่ดีดูดีขึ้นได้
คะแนน

ฉันเห็นด้วยกับสิ่งนี้อย่างเต็มที่ มันเป็นก้าวที่ดีในการแก้ไขโค้ดที่ไม่ดี คลาสพระเจ้าเป็นสภาพอากาศระดับเทพเจ้าที่มันแพร่กระจายในหลายไฟล์หรือไม่
Jimbo

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

    ในการตรวจสอบจุดที่ 4 เพียงแค่สร้างโครงการ winform และรวมบรรทัดนี้หลังจากตัวสร้าง Form1 และลองรวบรวมรหัส

    partial void Ontest(string s);

นี่คือบางจุดที่ต้องพิจารณาขณะใช้คลาสบางส่วน: -

  1. ใช้คีย์เวิร์ดบางส่วนในแต่ละส่วนของคลาสบางส่วน
  2. ชื่อของแต่ละส่วนของคลาสบางส่วนควรเหมือนกัน แต่ชื่อไฟล์ต้นฉบับสำหรับแต่ละส่วนของคลาสบางส่วนอาจแตกต่างกัน
  3. ทุกส่วนของคลาสบางส่วนควรอยู่ในเนมสเปซเดียวกัน
  4. แต่ละส่วนของคลาสบางส่วนควรอยู่ในแอสเซมบลีที่เหมือนกันหรือ DLL อีกนัยหนึ่งคุณไม่สามารถสร้างคลาสบางส่วนในไฟล์ต้นฉบับจากโครงการไลบรารีคลาสอื่น
  5. แต่ละส่วนของคลาสบางส่วนจะต้องมีความสามารถในการเข้าถึงเหมือนกัน (เช่น: ส่วนตัวสาธารณะหรือได้รับการคุ้มครอง)
  6. ถ้าคุณสืบทอดคลาสหรือส่วนต่อประสานบนคลาสบางส่วนมันจะถูกสืบทอดโดยทุกส่วนของคลาสบางส่วนนั้น
  7. หากส่วนหนึ่งของชั้นบางส่วนถูกผนึกไว้ชั้นเรียนทั้งหมดจะถูกผนึก
  8. หากส่วนหนึ่งของคลาสบางส่วนเป็นนามธรรมจากนั้นทั้งชั้นจะได้รับการพิจารณาเป็นระดับนามธรรม

1
มีปัญหาในการแก้ไขคลาสบางส่วนที่สร้างจาก Entity Framework หรือไม่? ฉันต้องการเปลี่ยนชื่อคลาสที่สร้างจากตาราง
MarceloBarbosa

ฉันมีความกังวลเดียวกัน ฉันต้องการทราบถึงประโยชน์ "ถ้ามี" ที่คลาสบางส่วนมีเมื่อสร้างโมเดลที่ Entity Framework จะใช้เพื่อสร้างฐานข้อมูลของฉันจาก Code First perspective / แนวทาง / การนำไปใช้ ... คุณมีอะไร
Chef_Code

@JimBalter โดยผ่านลิงค์นี้msdn.microsoft.com/en-us/library/6b0scde8(v=vs.110).aspx นี้ระบุว่าหากไม่มีการใช้งานปัจจุบันคอมไพเลอร์จะลบชิ้นส่วนของรหัสและไม่มีข้อผิดพลาดเวลารวบรวมจะได้รับ
hellowahab

ถ้าคุณสืบทอดคลาสหรือส่วนต่อประสานบนคลาสบางส่วนมันจะถูกสืบทอดโดยทุกส่วนของคลาสบางส่วนนั้น
ถั่วแดง

56

การใช้งานที่ยอดเยี่ยมอย่างหนึ่งคือการแยกรหัสที่สร้างขึ้นจากรหัสที่เขียนด้วยลายมือที่อยู่ในระดับเดียวกัน

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

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


21

มันเป็นความจริงที่ Partial Class ใช้ในการสร้างรหัสอัตโนมัติการใช้งานหนึ่งครั้งสามารถรักษาไฟล์คลาสขนาดใหญ่ซึ่งอาจมีโค้ดหลายพันบรรทัด คุณไม่มีทางรู้ว่าคลาสของคุณอาจลงท้ายด้วย 10,000 บรรทัดและคุณไม่ต้องการสร้างคลาสใหม่ด้วยชื่ออื่น

public partial class Product
{
    // 50 business logic embedded in methods and properties..
}

public partial class Product
{
    // another 50 business logic embedded in methods and properties..
}
//finally compile with product.class file.

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

Product1.cs

public partial class Product
{
    //you are writing the business logic for fast moving product
}

Product2.cs

public partial class Product
{
    // Another developer writing some business logic...
}

หวังว่ามันจะสมเหตุสมผล!


13

คลาสบางส่วนขยายหลายไฟล์

คุณจะใช้โมดิฟายเออร์บางส่วนในการประกาศคลาส C # ได้อย่างไร

ด้วยคลาสบางส่วนคุณสามารถแยกคลาสออกเป็นหลายไฟล์ได้ มักจะทำโดยผู้สร้างรหัส

ตัวอย่าง

ด้วยคลาส C # ปกติคุณไม่สามารถประกาศคลาสในสองไฟล์แยกกันในโครงการเดียวกัน แต่ด้วยpartialตัวดัดแปลงคุณสามารถ

สิ่งนี้มีประโยชน์หากไฟล์หนึ่งมีการแก้ไขโดยทั่วไปและไฟล์อื่น ๆ ถูกสร้างโดยเครื่องหรือแก้ไขได้ยาก

นี่คือตัวอย่างที่จะชี้แจง:

class Program
{
    static void Main()
    {
        A.A1();
        A.A2();
    }
}

เนื้อหาของไฟล์ A1.cs: C #

using System;

partial class A
{
    public static void A1()
    {
        Console.WriteLine("A1");
    }
}

เนื้อหาของไฟล์ A2.cs: C #

using System;

partial class A
{
    public static void A2()
    {
        Console.WriteLine("A2");
    }
}

เอาท์พุท:

A1
A2

ต้องการบางส่วนที่นี่

หากคุณลบpartialตัวดัดแปลงคุณจะได้รับข้อผิดพลาดที่มีข้อความนี้:

[เนมสเปซ ' <global namespace>' มีคำจำกัดความสำหรับ ' A'] อยู่แล้ว

เคล็ดลับ:

ในการแก้ไขปัญหานี้คุณสามารถใช้partialคำหลักหรือเปลี่ยนชื่อคลาสได้

คอมไพเลอร์ C # จะจัดการกับคลาสบางส่วนได้อย่างไร

หากคุณถอดโปรแกรมข้างต้น (โดยใช้ IL Disassembler) คุณจะเห็นว่าไฟล์ A1.cs และ A2.cs ถูกกำจัด คุณจะพบว่าคลาส A นั้นมีอยู่

คลาส A จะมีวิธีการ A1 และ A2 ในบล็อกรหัสเดียวกัน ทั้งสองเรียนรวมเข้าเป็นหนึ่งเดียว

รวบรวมผลลัพธ์ของ A1.cs และ A2.cs: C #

internal class A
{
    // Methods
    public static void A1()
    {
        Console.WriteLine("A1");
    }

    public static void A2()
    {
        Console.WriteLine("A2");
    }
}

สรุป

  • คลาสบางส่วนสามารถทำให้สถานการณ์การเขียนโปรแกรม C # ง่ายขึ้น
  • มักใช้ใน Visual Studio เมื่อสร้างโปรแกรม Windows Forms / WPF
  • รหัส C # ที่สร้างโดยเครื่องจักรนั้นแยกจากกัน
  • หรือคุณสามารถหาคำอธิบายทั้งหมดที่นี่

2
ตัวอย่างที่ดีและเอกสารที่ดี
Chef_Code

1
นี่เป็นคำอธิบายที่ง่ายที่สุดในการติดตาม IMO
Yusha

12

รักษาทุกสิ่งให้สะอาดที่สุดเท่าที่จะเป็นไปได้เมื่อทำงานกับคลาสที่มีขนาดใหญ่หรือเมื่อทำงานเป็นทีมคุณสามารถแก้ไขได้โดยไม่ต้องลบล้าง (หรือยอมรับการเปลี่ยนแปลงเสมอ)


11

การใช้งานหลักสำหรับคลาสบางส่วนอยู่กับรหัสที่สร้างขึ้น หากคุณดูที่เครือข่าย WPF (Windows Presentation Foundation) คุณจะกำหนด UI ของคุณด้วยมาร์กอัป (XML) มาร์กอัปนั้นรวบรวมเป็นคลาสบางส่วน คุณกรอกรหัสด้วยคลาสบางส่วนของคุณเอง


8

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

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

MyProvider.cs - ตรรกะหลัก

MyProvider.Forum.cs - วิธีการเฉพาะสำหรับฟอรัม

MyProvider.Product.cs - วิธีการสำหรับผลิตภัณฑ์

มันเป็นอีกวิธีหนึ่งในการจัดระเบียบสิ่งต่าง ๆ

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


2
ฉันจะสนับสนุนบางส่วนของเป็นหินก้าวสู่ refactoring (จุดทั้งหมดของคำตอบของฉัน) แต่จะไม่แนะนำให้พวกเขาเป็นทางออกที่แท้จริงในการเขียนรหัสสะอาด หากชั้นบางส่วนแยกจากกันอย่างหมดจดจากความกังวลอื่น ๆ ของชั้นเรียนแล้วทำไมไม่ลองใช้ความพยายามเล็กน้อยในการโปรโมตชั้นเรียนแบบแยกเดี่ยว
STW

@STW: อาจเป็นไปได้ว่าอินสแตนซ์ของวัตถุจำนวนมากถูกสร้างและใช้สำหรับงานต่าง ๆ การแยกงานต่าง ๆ ออกเป็นคลาสที่แตกต่างกันนั้นจะต้องมีการติดตามว่าอินสแตนซ์ใดที่ใช้สำหรับงานใด - อาจเป็นงานที่ใหญ่กว่าการย้ายบล็อกโค้ดระหว่างโมดูลซอร์ส
supercat

4
@supercat - ฉันเข้าใจทั้งหมด แต่การทำความสะอาดชนิดของปาเก็ตตี้ที่ควรจะดำเนินการ ฉันมีรอยแผลเป็นมากมายจากการทำความสะอาดโค้ดประเภทนั้นและจะไม่สนับสนุนให้ทิ้งไว้เบื้องหลัง ระเบียบประเภทเหล่านั้นรับประกันว่าจะสร้างปัญหาอย่างต่อเนื่องและผลตอบแทนระยะยาวมีขนาดใหญ่มากเมื่อเทียบกับการละเลยปัญหา รหัสเช่นนั้นไม่มี "กลิ่น" มันเหมือนขยะที่ทิ้งขยะ
STW

1
@supercat - ฉันพยายามที่จะมีคุณสมบัติด้วย "ถ้าบางส่วนแยกออกจากกันอย่างหมดจดจากความกังวลอื่น ๆ ... แล้วมันเป็นความพยายามเล็กน้อย" การได้รับความเจ็บปวดจากการถูกแกะสลักจะช่วยให้คุณประหยัดค่าบำรุงรักษาได้ในระยะยาวหากไม่ใช่ Rogaine
STW

2
บังเอิญฉันกำลังเล่นกับพยายามแก้ไข Roslyn วันนี้และมันเขียนด้วยการใช้งานที่กว้างขวางของชั้นเรียนบางส่วน คลาสหลักจำนวนมากใน Roslyn ถูกกำหนดเป็นคลาสบางส่วนในหลายไฟล์ และอย่างน้อยก็โรสลินเขียนโดยคนที่ฉันอย่างน้อยก็พิจารณาว่าเป็นโปรแกรมเมอร์ C # ที่ฉลาดมาก
RenniePet

8

เป็นทางเลือกแทนคำสั่ง pre-compiler

หากคุณใช้คำสั่ง pre-compiler (เช่น#IF DEBUG) จากนั้นคุณจะพบกับโค้ดที่ดูน่าสนใจบางอย่างที่ถูกรวมเข้ากับโค้ดรีลีสจริงของคุณ

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


Monogame ใช้กลยุทธ์นี้
Zamboni

6

การอ้างอิงบริการเป็นอีกตัวอย่างหนึ่งที่คลาสบางส่วนมีประโยชน์ในการแยกรหัสที่สร้างขึ้นจากรหัสที่ผู้ใช้สร้างขึ้น

คุณสามารถ "ขยาย" คลาสบริการโดยไม่ต้องเขียนทับมันเมื่อคุณอัปเดตข้อมูลอ้างอิงบริการ


6

การใช้งานอื่นที่ฉันเห็นคือ

การขยายคลาสนามธรรมขนาดใหญ่เกี่ยวกับตรรกะการเข้าถึงข้อมูล

ฉันมีไฟล์ต่าง ๆ ที่มีชื่อ Post.cs, Comment.cs, Pages.cs ...

in Post.cs 

public partial class XMLDAO :BigAbstractClass
{
// CRUD methods of post..
}


in Comment.cs 

public partial class XMLDAO :BigAbstractClass
{
// CRUD methods of comment..
}

in Pages.cs 

public partial class XMLDAO :BigAbstractClass
{
// CRUD methods of Pages..
}

6

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

ตัวอย่างหนึ่งให้ดูที่ชั้น C # System.Math ... ที่ระดับ ฉันจะไม่พยายามทำมากกว่า 70 วิธีให้เป็นไฟล์รหัสเดียวกัน มันคงเป็นฝันร้ายที่ต้องดูแล

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

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

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

ฉันจะระมัดระวังในการใช้คลาสบางส่วนและเก็บเลย์เอาต์ของรหัสไฟล์ทั้งหมดที่สอดคล้องกันตลอดโครงการเมื่อทำสิ่งนี้ เช่นวางสาธารณะ enums คลาสใด ๆ และสมาชิกส่วนตัวของคลาสลงใน Common.cs หรือไฟล์ที่มีชื่อคล้ายกันในโฟลเดอร์แทนที่จะกระจายออกไปทั่วทั้งไฟล์เว้นแต่พวกเขาจะเจาะจงเฉพาะไฟล์บางส่วนเท่านั้นที่มีอยู่

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


4

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

คลาสสาธารณะบางส่วน zzFileConverterRegistrar
    ลงทะเบียนกิจกรรม (ByVal mainConverter เป็น zzFileConverter)
    ย่อย registerAll (ByVal mainConverter เป็น zzFileConverter)
        RaiseEvent Register (mainConverter)
    ส่วนท้าย
จบชั้น

แต่ละโมดูลที่ต้องการลงทะเบียนตัวแปลงไฟล์อย่างน้อยหนึ่งประเภทอาจมีสิ่งต่อไปนี้:

คลาสสาธารณะบางส่วน zzFileConverterRegistrar
    Private Sub RegisterGif (ByVal mainConverter เป็น zzFileConverter) จัดการ Me.Register
        mainConverter.RegisterConverter ("GIF", GifConverter.NewFactory))
    ส่วนท้าย
จบชั้น

โปรดทราบว่าคลาสตัวแปลงไฟล์หลักไม่ได้ "เปิดเผย" แต่เป็นเพียงการเปิดเผยคลาส stub เล็กน้อยที่โมดูล add-in สามารถเชื่อมต่อ มีความเสี่ยงเล็กน้อยในการตั้งชื่อความขัดแย้ง แต่ถ้ารูทีน "register" ของ Add-in แต่ละโมดูลถูกตั้งชื่อตามประเภทของไฟล์ที่เกี่ยวข้องกับพวกเขาอาจจะไม่ก่อปัญหา หนึ่งสามารถติด GUID ในชื่อของรูทีนย่อยการลงทะเบียนหากมีความกังวลเกี่ยวกับสิ่งดังกล่าว

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

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

  RegisterConverter ("GIF", GifConvertor.NewFactory)
  RegisterConverter ("BMP", BmpConvertor.Factory)
  RegisterConverter ("JPEG", JpegConvertor.NewFactory)

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


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

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

1
ความเสี่ยงมีอยู่ค่อนข้างดีในสายงานของคุณ "... หากพวกเขาไม่ทำอะไรเลย [... ] ยกเว้น ... " ความปลอดภัยและความมั่นคงนั้นดำเนินการโดยนักพัฒนาต่อไปนี้ตามแบบแผนและให้ความมั่นใจ 0% หากกรณีการใช้งานของคุณคือการมีพวกเขารวบรวมใน (ที่ถูกต้องสมบูรณ์เพียงแค่จะต้องมีจิตสำนึกค้าออก) แล้วทำไมไม่เพียงแค่มีโมดูลที่กำหนดไว้ในการเรียนการแยกและการดำเนินการบางส่วนIModuleอินเตอร์เฟซ?
STW

ดูเหมือนว่ากรณีของการเป็น "ฉลาด" ไปเสีย นี่ไม่ใช่ "โมดูล" แต่เป็นคลาสเดี่ยวที่มีพฤติกรรมและความรับผิดชอบหลายอย่างรวมอยู่ในที่เดียวในเวลารวบรวม มีวิธีที่ดีกว่ามากในการทำเช่นนี้ - คุณสามารถใช้ Reflection เพื่อสแกนแอสเซมบลีที่รวบรวมสำหรับคลาสที่ใช้งานIModuleคุณสามารถใช้ปลั๊กอินเฟรมเวิร์กเช่น MEF (เพียงหนึ่งในหลาย ๆ ) ฯลฯ เป็นต้น
STW

3

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

สิ่งเหล่านี้ผลักดันให้คอมไพล์เกิดความขัดแย้งผสาน ฉันไม่พบวิธีบอกเครื่องมือผสานให้ใช้วิธีการใหม่เป็นบล็อกโค้ดแบบสมบูรณ์

คลาสบางส่วนในส่วนนี้ช่วยให้นักพัฒนาสามารถยึดไฟล์เวอร์ชันของพวกเขาและเราสามารถรวมพวกเขากลับมาในภายหลังด้วยมือ

ตัวอย่าง -

  • MainClass.cs - เก็บฟิลด์คอนสตรัคเตอร์ ฯลฯ
  • MainClass1.cs - รหัสใหม่ของนักพัฒนาในขณะที่ใช้งาน
  • MainClass2.cs - เป็นอีกหนึ่งคลาสสำหรับนักพัฒนาสำหรับรหัสใหม่ของพวกเขา

3

จากMSDN :

1. เวลารวบรวมคุณสมบัติของคำจำกัดความชนิดบางส่วนจะถูกรวมเข้าด้วยกัน ตัวอย่างเช่นพิจารณาการประกาศต่อไปนี้:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

พวกเขาจะเทียบเท่ากับการประกาศดังต่อไปนี้:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

ต่อไปนี้จะถูกผสานจากคำจำกัดความบางส่วนทั้งหมด:

  • ความคิดเห็น XML

  • อินเตอร์เฟซ

  • คุณสมบัติพารามิเตอร์ประเภททั่วไป

  • คุณลักษณะคลาส

  • สมาชิก

2. สิ่งอื่น ๆ คลาสที่ซ้อนกันบางส่วนสามารถเป็นบางส่วนได้:

partial class ClassWithNestedClass
{
    partial class NestedClass { }
}

partial class ClassWithNestedClass
{
    partial class NestedClass { }
}

1

นี่คือรายการของข้อดีบางส่วนของคลาสบางส่วน

คุณสามารถแยกรหัสการออกแบบ UI และรหัสตรรกะทางธุรกิจเพื่อให้ง่ายต่อการอ่านและทำความเข้าใจ ตัวอย่างเช่นคุณกำลังพัฒนาเว็บแอปพลิเคชันโดยใช้ Visual Studio และเพิ่มเว็บฟอร์มใหม่จากนั้นมีไฟล์ต้นฉบับสองไฟล์คือ "aspx.cs" และ "aspx.designer.cs" ไฟล์สองไฟล์นี้มีคลาสเดียวกันกับคำหลักบางส่วน คลาส ".aspx.cs" มีรหัสตรรกะทางธุรกิจในขณะที่ "aspx.designer.cs" มีข้อกำหนดการควบคุมส่วนต่อประสานผู้ใช้

เมื่อทำงานกับซอร์สที่สร้างขึ้นโดยอัตโนมัติคุณสามารถเพิ่มโค้ดลงในคลาสได้โดยไม่ต้องสร้างไฟล์ต้นฉบับอีก ตัวอย่างเช่นคุณกำลังทำงานกับ LINQ ไปยัง SQL และสร้างไฟล์ DBML ตอนนี้เมื่อคุณลากและวางตารางมันจะสร้างคลาสบางส่วนใน designer.cs และคอลัมน์ตารางทั้งหมดมีคุณสมบัติในคลาส คุณต้องการคอลัมน์เพิ่มเติมในตารางนี้เพื่อผูกบนตาราง UI แต่คุณไม่ต้องการเพิ่มคอลัมน์ใหม่ลงในตารางฐานข้อมูลเพื่อให้คุณสามารถสร้างไฟล์ต้นฉบับแยกต่างหากสำหรับคลาสนี้ที่มีคุณสมบัติใหม่สำหรับคอลัมน์นั้นและจะ เป็นชนชั้นบางส่วน ดังนั้นจะมีผลต่อการแมประหว่างตารางฐานข้อมูลและเอนทิตี DBML แต่คุณสามารถรับฟิลด์พิเศษได้อย่างง่ายดาย หมายความว่าคุณสามารถเขียนโค้ดด้วยตัวเองโดยไม่ต้องยุ่งกับรหัสที่ระบบสร้างขึ้น

นักพัฒนามากกว่าหนึ่งคนสามารถเขียนรหัสสำหรับชั้นเรียนได้พร้อมกัน

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


1

เมื่อใดก็ตามที่ฉันมีคลาสที่มีคลาสซ้อนอยู่ที่มีขนาด / ความซับซ้อนที่มีนัยสำคัญใด ๆ ฉันจะเลือกคลาสเป็น partialและวางคลาสที่ซ้อนกันในไฟล์แยกต่างหาก ฉันตั้งชื่อไฟล์ที่มีคลาสที่ซ้อนกันโดยใช้กฎ: [class name]. [nested class name] .cs

บล็อก MSDN ต่อไปนี้อธิบายการใช้คลาสบางส่วนที่มีคลาสที่ซ้อนกันเพื่อการบำรุงรักษา: http://blogs.msdn.com/b/marcelolr/archive/2009/04/13/using-partial-classes-with-nested-classes-for- maintainability.aspx


1

ฉันรู้ว่าคำถามนี้เก่ามาก แต่ฉันต้องการเพิ่มเวลาเรียนบางส่วน

เหตุผลหนึ่งที่ฉันใช้คลาสส่วนตัวบางส่วนคือเมื่อฉันสร้างการเชื่อมสำหรับโปรแกรมโดยเฉพาะอย่างยิ่งเครื่องของรัฐ

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

ชั้นเรียนบางส่วนจะทำลายสิ่งนี้ให้ฉันและช่วยฉันในการค้นหาวิธีการอย่างรวดเร็ว


0

มีการแนะนำคลาสบางส่วนเพื่อช่วยในการสร้างโค้ดดังนั้นเรา (ผู้ใช้) จะไม่สูญเสียการทำงาน / เปลี่ยนแปลงคลาสที่สร้างขึ้นเช่นคลาส. designer.cs ของ ASP.NET ทุกครั้งที่เราสร้างเครื่องมือขึ้นมาใหม่เกือบทั้งหมด รหัส LINQ, EntityFrameworks, ASP.NET ใช้คลาสบางส่วนสำหรับรหัสที่สร้างขึ้นเพื่อให้เราสามารถเพิ่มหรือแก้ไขตรรกะของรหัสที่สร้างขึ้นเหล่านี้ได้อย่างปลอดภัยโดยใช้ประโยชน์จากคลาสและวิธีการบางส่วน แต่อย่างระมัดระวังก่อนที่คุณจะเพิ่มเนื้อหาลงในโค้ดที่สร้างขึ้น มันจะง่ายกว่าถ้าเราทำลายโครงสร้าง แต่แย่ที่สุดถ้าเราแนะนำข้อผิดพลาด runtime สำหรับรายละเอียดเพิ่มเติมโปรดตรวจสอบที่http://www.4guysfromrolla.com/articles/071509-1.aspx


0

ฉันสังเกตสองประเพณีซึ่งฉันไม่สามารถหาคำตอบได้อย่างชัดเจน

จัดกลุ่มรายการคลาส

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

public class MyClass{  
  //Member variables
  //Constructors
  //Properties
  //Methods
}

ด้วยคลาสบางส่วนเราสามารถไปอีกขั้นและแยกส่วนออกเป็นไฟล์แยก ตามแบบแผนทีมอาจต่อท้ายแต่ละไฟล์ด้วยส่วนที่เกี่ยวข้อง ดังนั้นในข้างต้นเราจะมีสิ่งที่ชอบ: MyClassMembers.cs, MyClassConstructors.cs, MyClassProperties.cs, MyClassMethods.cs

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

//Methods - See partial class

การจัดการขอบเขตการใช้คำสั่ง / Namespace

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


มีกลไกในการแก้ไขการชนของเนมสเปซตัวอย่างเช่นการเปลี่ยนชื่อเนมสเปซโดยใช้using Library1 = The.Namespace.You.Needหรือglobal::Root.Of.Namespace
fjch1997

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