เหตุใดฉันจึงไม่สามารถรับคลาสแบบสแตติกได้


224

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

แต่ดูเหมือนว่าฉันไม่สามารถประกาศการสืบทอดสำหรับคลาสสแตติก

อะไรแบบนั้น:

public static class Base
{
}

public static class Inherited : Base
{
}

จะไม่ทำงาน.

ทำไมนักออกแบบของภาษาจึงปิดโอกาสนั้น


คำตอบ:


174

การอ้างอิงจากที่นี่ :

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

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

(Mads Torgersen, PM ภาษา C #)

ความคิดเห็นอื่น ๆ จาก channel9

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

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

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

(littleguru)

และเป็นความคิดที่มีค่าLittleguruมี "วิธีแก้ปัญหา" บางส่วนสำหรับปัญหานี้: รูปแบบซิงเกิล


92
ขาดจินตนาการด้าน Torgersen จริง ๆ ผมมีเหตุผลที่ดีงามเพื่อต้องการที่จะทำนี้ :)
Thorarin

10
แล้วเรื่องนี้ล่ะ คุณมี dll ที่ไม่ใช่โอเพ่นซอร์ส / คุณไม่มีสิทธิ์เข้าถึงซอร์สของมันสมมติว่า NUnit คุณต้องการขยายเป็นคลาส Assert เพื่อให้มีวิธีเช่น Throws <> (Action a) (ใช่แล้วมีอยู่ด้วย แต่เมื่อถึงจุดหนึ่งก็ไม่ได้เกิดขึ้น) คุณสามารถเพิ่ม Assert: NUnit.Framework.Assert ในโครงการของคุณ ชั้นเรียนแล้วเพิ่มวิธีการพ่น แก้ไขปัญหา. มันสะอาดกว่าที่จะใช้ในโค้ดเช่นกัน ... แทนที่จะต้องใช้ชื่อคลาสอื่นและจำชื่อคลาสนั้นได้เพียงพิมพ์ Assert และดูวิธีการที่มี
user420667

4
@KonradMorawski เป็นไปไม่ได้ที่จะเขียนวิธีการขยายสำหรับคลาสคงที่ stackoverflow.com/questions/249222/…
Martin Braun

2
@odiX แน่นอน คุณเข้าใจฉันผิดที่นี่ สิ่งที่ฉันหมายถึงคือการทำงานที่จำเป็นในสถานการณ์ที่อธิบายโดย user420667 สามารถให้ได้ ( ในอนาคต ) เพียงเล็กน้อยเท่าที่อนุญาตวิธีการขยายสำหรับคลาสแบบคงที่ ไม่จำเป็นต้องสืบทอดมรดก นั่นเป็นเหตุผลที่สถานการณ์ของเขาไม่ได้ตีฉันเป็นเหตุผลที่ดีมากสำหรับการแนะนำมรดกคงที่ หากต้องแก้ไข C # ในด้านนี้ทำไมต้องมีการออกแบบใหม่ที่สำคัญเมื่อผู้เยาว์จะดีในทางปฏิบัติ
Konrad Morawski

5
@Learner มันไม่ยุติธรรมเลย ใน. Net ทุกสิ่งสืบทอดมาจากobjectและทุกคนคาดว่าจะรู้ว่า ดังนั้นคลาสสแตติกจะสืบทอดจากเสมอobjectไม่ว่าคุณจะระบุอย่างชัดเจนหรือไม่
RenniePet

71

เหตุผลหลักที่คุณไม่สามารถสืบทอดคลาสแบบสแตติกได้คือพวกมันเป็นนามธรรมและปิดผนึก

ดังนั้นนี่คือ:

static class Foo { }

รวบรวมไปยัง IL นี้:

.class private abstract auto ansi sealed beforefieldinit Foo
  extends [mscorlib]System.Object
 {
 }

17
คุณกำลังบอกว่าสถิตถูกนำมาใช้เป็นนามธรรม + ปิดผนึก เขาต้องการที่จะรู้ว่าทำไมสิ่งนี้ถึงเกิดขึ้น ทำไมมันปิดผนึก
ลูคัส

22
นี่ไม่ได้ตอบคำถามทุกข้อ เป็นเพียงการทบทวนปัญหาที่เขาถาม
Igby Largeman

28
ดี OP ควรจะได้ถามว่า "ทำไมชั้นเรียนคงปิดสนิท" ไม่ได้ "ทำไมฉันไม่สามารถรับมรดกจากการเรียนแบบคงที่?" คำตอบที่เป็นของหลักสูตร"เพราะพวกเขากำลังปิดผนึก" คำตอบนี้ได้รับการโหวตของฉัน
Alex Budovski

6
ขอบคุณที่แบ่งปันคลาสแบบคงที่ได้รับการรวบรวมโดยอัตโนมัติเป็นคลาสที่ปิดผนึก - ฉันสงสัยว่าเกิดขึ้นได้อย่างไร / เมื่อไร!
ทำเครื่องหมาย

23
@AlexBudovski: คำตอบนี้ถูกต้อง แต่ไร้ประโยชน์เหมือนการบอกคนที่หายไปว่า "คุณอยู่ตรงหน้าฉัน" เมื่อพวกเขาถามคุณว่า "ฉันอยู่ที่ไหน"
DeepSpace101

24

คิดแบบนี้: คุณเข้าถึงสมาชิกคงที่ผ่านชื่อประเภทเช่นนี้

MyStaticType.MyStaticMember();

หากคุณได้รับมรดกจากคลาสนั้นคุณจะต้องเข้าถึงผ่านทางชื่อประเภทใหม่:

MyNewType.MyStaticMember();

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

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

บางทีคุณต้องการที่จะเพิ่มวิธีการในประเภทคงที่ที่มีอยู่ คุณสามารถทำได้โดยใช้วิธีการขยาย

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

ดังนั้นในที่สุดคุณจะไม่ได้รับอะไรเลยจากการสืบทอดคลาสที่คงที่


5
คุณไม่สามารถเพิ่มวิธีการในประเภทคงที่ที่มีอยู่ผ่านวิธีการขยาย โปรดดูความคิดเห็นของฉันเกี่ยวกับคำตอบที่ยอมรับสำหรับตัวอย่างการใช้ที่ต้องการ (โดยทั่วไปคุณต้องการเปลี่ยนชื่อสิ่งที่คุณตั้งชื่อว่า MyNewType เป็น MyStaticType ดังนั้น MyStaticType: OldProject.MyStaticType)
user420667

2
หนึ่งสามารถกำหนดความสัมพันธ์การสืบทอดกับชนิดสแตติกและสมาชิกแบบสแตติกเสมือนในแบบที่SomeClass<T> where T:Fooสามารถเข้าถึงสมาชิกของFooและถ้าTเป็นคลาสที่Fooแทนที่สมาชิกแบบสแตติกเสมือนของคลาสทั่วไปจะใช้การแทนที่เหล่านั้น มันอาจจะเป็นไปได้ที่จะกำหนดอนุสัญญาผ่านภาษาที่สามารถทำได้ในรูปแบบที่เข้ากันได้กับ CLR ปัจจุบัน (เช่นคลาสที่มีสมาชิกดังกล่าวควรกำหนดคลาสที่ไม่คงที่ที่มีการป้องกันซึ่งมีสมาชิกอินสแตนซ์ดังกล่าว ถืออินสแตนซ์ของประเภทนั้น)
supercat

ฉันพบว่าตัวเองมีกรณีที่ฉันเชื่อว่าการสืบทอดคลาสแบบสแตติกเป็นสิ่งที่ถูกต้องแม้ว่าจะเห็นได้ชัดว่าคุณสามารถเข้าถึงได้ ฉันมีคลาสคงที่สำหรับการส่งข้อมูลดิบไปยังเครื่องพิมพ์ (สำหรับพูดคุยกับเครื่องพิมพ์ฉลากอุตสาหกรรม) มันมีการประกาศของ Windows API มากมาย ตอนนี้ฉันพบว่าตัวเองกำลังเขียนอีกคลาสหนึ่งเพื่อทำกับเครื่องพิมพ์ที่ต้องการการเรียก API เดียวกัน รวมกัน? ไม่ดี. ประกาศพวกเขาสองครั้ง? น่าเกลียด สืบทอด? ดี แต่ไม่อนุญาต
Loren Pechtel

3

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


ฉันมีโหลดเดอร์ทั่วไปที่รับคลาสเป็นประเภท คลาสนั้นมีวิธีการช่วยเหลือ 5 วิธีและ 2 วิธีที่ส่งคืนสตริง (ชื่อและคำอธิบาย) ฉันอาจเลือกผิด (ฉันคิดอย่างนั้น) แต่ทางออกเดียวที่ฉันพบคือการยกตัวอย่างคลาสในตัวโหลดทั่วไปเพื่อเข้าถึงวิธีการ ... meh
Aneves

ทางเลือกจะเป็นพจนานุกรมยักษ์ฉันเดา นอกจากนี้เมื่อคุณพูดว่า "สิ่งที่คุณต้องการบรรลุ" คุณควรพูดว่า "สิ่งที่คุณต้องการจะทำ" หรือสิ่งที่คล้ายกัน
Aneves

3

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


2

แม้ว่าคุณสามารถเข้าถึงสมาชิกแบบคงที่ "สืบทอด" ผ่านชื่อคลาสที่สืบทอด แต่สมาชิกแบบสแตติกจะไม่สืบทอดจริง ๆ นี่เป็นส่วนหนึ่งที่ว่าทำไมพวกเขาจึงไม่สามารถเสมือนหรือเป็นนามธรรมและไม่สามารถแทนที่ได้ ในตัวอย่างของคุณถ้าคุณประกาศ Base.Method () คอมไพเลอร์จะแมปการเรียกใช้ Inherited.Method () กลับไปที่ Base.Method () ต่อไป คุณอาจเรียก Base.Method () อย่างชัดเจนเช่นกัน คุณสามารถเขียนการทดสอบขนาดเล็กและดูผลลัพธ์ด้วย Reflector

ดังนั้น ... ถ้าคุณไม่สามารถรับสมาชิกแบบสแตติกได้และถ้าคลาสแบบสแตติกสามารถมีสมาชิกแบบสแตติกได้เท่านั้นสิ่งที่ดีในการรับคลาสแบบสแตติกจะทำอย่างไร


1

อืม ... มันจะแตกต่างกันมากถ้าคุณเพิ่งมีคลาสแบบไม่คงที่ที่เต็มไปด้วยวิธีการแบบคงที่ .. ?


2
นั่นคือสิ่งที่เหลือไว้สำหรับฉัน ฉันทำอย่างนี้ และฉันไม่ชอบมัน
ผู้ใช้

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

ในชั้นเรียนไม่คงเต็มไปด้วยวิธีการแบบคงคุณไม่สามารถใส่วิธีการขยาย :)
ยาคุบบSzułakiewicz

1

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

public class TestClass<T>
{
    protected TestClass()
    { }

    public static T Add(T x, T y)
    {
        return (dynamic)x + (dynamic)y;
    }
}

public class TestClass : TestClass<double>
{
    // Inherited classes will also need to have protected constructors to prevent people from creating instances of them.
    protected TestClass()
    { }
}

TestClass.Add(3.0, 4.0)
TestClass<int>.Add(3, 4)

// Creating a class instance is not allowed because the constructors are inaccessible.
// new TestClass();
// new TestClass<int>();

น่าเสียดายเนื่องจากข้อ จำกัด ภาษา "โดยการออกแบบ" เราไม่สามารถทำได้:

public static class TestClass<T>
{
    public static T Add(T x, T y)
    {
        return (dynamic)x + (dynamic)y;
    }
}

public static class TestClass : TestClass<double>
{
}

1

คุณสามารถทำสิ่งที่จะมีลักษณะเหมือนมรดกที่คงที่

นี่คือเคล็ดลับ:

public abstract class StaticBase<TSuccessor>
    where TSuccessor : StaticBase<TSuccessor>, new()
{
    protected static readonly TSuccessor Instance = new TSuccessor();
}

จากนั้นคุณสามารถทำสิ่งนี้:

public class Base : StaticBase<Base>
{
    public Base()
    {
    }

    public void MethodA()
    {
    }
}

public class Inherited : Base
{
    private Inherited()
    {
    }

    public new static void MethodA()
    {
        Instance.MethodA();
    }
}

Inheritedระดับไม่คงที่ตัวเอง แต่เราไม่อนุญาตให้มีการสร้างมันขึ้นมา มันได้รับการสร้างแบบคงที่ซึ่งสร้างBaseและคุณสมบัติและวิธีการทั้งหมดที่Baseมีอยู่เป็นแบบคงที่ ทีนี้สิ่งเดียวที่เหลือที่จะทำ wrappers คงที่สำหรับแต่ละวิธีและคุณสมบัติที่คุณต้องเปิดเผยให้กับบริบทคงที่ของคุณ

มีข้อเสียเช่นความต้องการในการสร้างวิธีการ wrapper คงที่และnewคำหลัก แต่วิธีการนี้ช่วยสนับสนุนบางสิ่งที่คล้ายกับการถ่ายทอดทางสถิต

ป.ล. เราใช้สิ่งนี้เพื่อสร้างแบบสอบถามที่คอมไพล์และสิ่งนี้สามารถแทนที่ด้วย ConcurrentDictionary แต่ฟิลด์แบบอ่านอย่างเดียวที่มีความปลอดภัยของเธรดนั้นดีพอ


1

คำตอบของฉัน: ตัวเลือกการออกแบบไม่ดี ;-)

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

ตัวอย่างเทียมสมมติว่าการสืบทอดแบบคงที่ถูกกำหนดในบางวิธี

public static class MyStaticBase
{
    SomeType AttributeBase;
}

public static class MyStaticChild : MyStaticBase
{
    SomeType AttributeChild;
}

จะนำไปสู่:

 // ...
 DoSomethingTo(MyStaticBase.AttributeBase);
// ...

ซึ่งสามารถ (จะ?) ส่งผลกระทบต่อการจัดเก็บข้อมูลเช่นเดียวกับ

// ...
DoSomethingTo(MyStaticChild.AttributeBase);
// ...

สับสนมาก!

แต่เดี๋ยวก่อน! คอมไพเลอร์จะจัดการกับ MyStaticBase และ MyStaticChild ที่มีลายเซ็นเดียวกันในทั้งสองวิธีอย่างไร หากเด็กแทนที่ตัวอย่างข้างต้นฉันจะไม่เปลี่ยนที่เก็บข้อมูลเดียวกันหรือไม่? สิ่งนี้นำไปสู่ความสับสนมากยิ่งขึ้น

ฉันเชื่อว่ามีเหตุผลพื้นที่ข้อมูลที่แข็งแกร่งสำหรับการสืบทอดแบบคงที่ จำกัด เพิ่มเติมเกี่ยวกับขีด จำกัด ในไม่ช้า pseudocode นี้แสดงค่า:

public static class MyStaticBase<T>
{
   public static T Payload;
   public static void Load(StorageSpecs);
   public static void Save(StorageSpecs);
   public static SomeType AttributeBase
   public static SomeType MethodBase(){/*...*/};
}

จากนั้นคุณจะได้รับ:

public static class MyStaticChild : MyStaticBase<MyChildPlayloadType>
{
   public static SomeType AttributeChild;
   public static SomeType SomeChildMethod(){/*...*/};
   // No need to create the PlayLoad, Load(), and Save().
   // You, 'should' be prevented from creating them, more on this in a sec...
} 

การใช้งานดูเหมือนว่า:

// ...
MyStaticChild.Load(FileNamePath);
MyStaticChild.Save(FileNamePath);
doSomeThing(MyStaticChild.Payload.Attribute);
doSomething(MyStaticChild.AttributeBase);
doSomeThing(MyStaticChild.AttributeChild);
// ...

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

Statics (singletons และรูปแบบอื่น ๆ ของ 'globals') มักจะเกิดขึ้นรอบ ๆ ที่เก็บข้อมูลการกำหนดค่า การสืบทอดแบบคงที่จะช่วยให้การจัดสรรความรับผิดชอบประเภทนี้จะแสดงอย่างหมดจดในไวยากรณ์เพื่อให้ตรงกับลำดับชั้นของการกำหนดค่า แม้ว่าอย่างที่ฉันแสดงมีความเป็นไปได้มากมายสำหรับความคลุมเครือขนาดใหญ่หากมีการนำแนวคิดการสืบทอดมรดกพื้นฐานมาใช้

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

  1. ไม่มีการแทนที่ของอะไร เด็กไม่สามารถแทนที่แอตทริบิวต์ฐาน, เขตข้อมูล, หรือวิธีการ, ... การบรรทุกเกินควรจะเป็นเรื่องปกติตราบใดที่มีความแตกต่างในการลงนามอนุญาตให้คอมไพเลอร์เพื่อเรียงลำดับ child vs base
  2. อนุญาตเฉพาะฐานแบบคงที่ทั่วไปคุณไม่สามารถสืบทอดจากฐานแบบคงที่ที่ไม่ใช่แบบทั่วไป

MyStaticBase<ChildPayload>.SomeBaseFieldคุณยังสามารถเปลี่ยนสาขาเดิมผ่านการอ้างอิงทั่วไป แต่คุณจะท้อใจเพราะจะต้องระบุประเภททั่วไป ในขณะที่การอ้างอิงของเด็กจะสะอาดกว่า:MyStaticChild.SomeBaseFieldในขณะที่การอ้างอิงที่เด็กจะทำความสะอาด:

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


0

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

ชั้นสามารถประกาศคงที่ซึ่งบ่งชี้ว่ามันมีเพียงสมาชิกคงที่ ไม่สามารถใช้คำหลักใหม่เพื่อสร้างอินสแตนซ์ของคลาสแบบสแตติก คลาสที่คงที่จะถูกโหลดโดยอัตโนมัติโดย. NET Framework ภาษาทั่วไปรันไทม์ (CLR) เมื่อโปรแกรมหรือ namespace ที่มีการโหลดชั้นเรียน

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

ต่อไปนี้เป็นคุณสมบัติหลักของคลาสคงที่:

  1. พวกเขามีสมาชิกแบบคงที่เท่านั้น

  2. ไม่สามารถสร้างอินสแตนซ์ได้

  3. พวกเขาถูกปิดผนึก

  4. พวกเขาไม่สามารถมี Instance Constructors (คู่มือการเขียนโปรแกรม C #)

ดังนั้นการสร้างคลาสสแตติกจึงเหมือนกับการสร้างคลาสที่มีสมาชิกแบบสแตติกและตัวสร้างส่วนตัวเท่านั้น คอนสตรัคส่วนตัวป้องกันไม่ให้ชั้นถูก instantiated

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

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


-1

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

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