ฉันจะให้ตัวออกแบบฟอร์ม Windows ของ Visual Studio 2008 แสดงผลแบบฟอร์มที่ใช้คลาสฐานนามธรรมได้อย่างไร


98

ฉันมีปัญหากับการควบคุมที่สืบทอดมาใน Windows Forms และต้องการคำแนะนำ

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

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

เมื่อฉันทำเครื่องหมายการควบคุมพื้นฐานเป็นนามธรรม Visual Studio 2008 Designer ปฏิเสธที่จะโหลดหน้าต่าง

มีวิธีทำให้นักออกแบบทำงานร่วมกับบทคัดย่อที่สร้างฐานควบคุมหรือไม่?

คำตอบ:


97

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

เราเปลี่ยนจากรหัสนี้ไปสู่ปัญหา

Form1 : Form

ปัญหา

public class Form1 : BaseForm
...
public abstract class BaseForm : Form

นี่คือที่มาของคำถามเริ่มต้น ดังที่ได้กล่าวไว้ก่อนหน้านี้เพื่อนคนหนึ่งชี้ให้เห็นว่าSystem.Windows.Forms.Formการใช้คลาสพื้นฐานที่เป็นนามธรรม เราสามารถค้นหา ...

พิสูจน์วิธีแก้ปัญหาที่ดีกว่า

จากสิ่งนี้เรารู้ว่าเป็นไปได้ที่นักออกแบบจะแสดงคลาสที่ใช้คลาสนามธรรมพื้นฐาน แต่ไม่สามารถแสดงคลาสนักออกแบบที่ใช้คลาสนามธรรมพื้นฐานได้ทันที จะต้องมีค่าสูงสุด 5 ในระหว่างนั้น แต่เราทดสอบนามธรรม 1 ชั้นและเริ่มหาวิธีแก้ปัญหานี้

โซลูชันเบื้องต้น

public class Form1 : MiddleClass
...
public class MiddleClass : BaseForm
... 
public abstract class BaseForm : Form
... 

สิ่งนี้ใช้งานได้จริงและนักออกแบบก็แสดงผลได้ดีแก้ไขปัญหาได้ .... ยกเว้นว่าคุณมีการสืบทอดระดับพิเศษในแอปพลิเคชันการผลิตของคุณซึ่งจำเป็นเพียงเพราะความไม่เพียงพอในตัวออกแบบ winforms!

นี่ไม่ใช่วิธีแก้ปัญหาที่แน่นอน 100% แต่ค่อนข้างดี โดยทั่วไปแล้วคุณ#if DEBUGจะใช้เพื่อหาโซลูชันที่ละเอียดอ่อน

โซลูชันการกลั่น

Form1.cs

#if DEBUG
public class Form1 : MiddleClass
#else 
public class Form1 : BaseForm
#endif
...

MiddleClass.cs

public class MiddleClass : BaseForm
... 

BaseForm.cs

public abstract class BaseForm : Form
... 

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

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

ทางออกเดียวที่แน่นอนคือถ้าคุณสามารถทดสอบโหมดการออกแบบผ่านคำสั่งพรีโปรเซสเซอร์


3
แบบฟอร์มและคลาสฐานนามธรรมของคุณมีตัวสร้างที่ไม่มีอาร์กิวเมนต์หรือไม่? นั่นคือทั้งหมดที่เราต้องเพิ่มเพื่อให้นักออกแบบทำงานเพื่อแสดงรูปแบบที่สืบทอดมาจากรูปแบบนามธรรม
เลขที่

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

1
โซลูชันของคุณใช้งานได้ดี ฉันไม่อยากจะเชื่อเลยว่า Visual Studio ต้องการให้คุณกระโดดผ่านห่วงดังกล่าวเพื่อทำสิ่งที่ธรรมดา ๆ
RB Davidson

1
แต่ถ้าฉันใช้ middleClass ซึ่งไม่ใช่คลาสนามธรรมแล้วใครก็ตามที่ได้รับคลาส middleClass ไม่ต้องใช้วิธีนามธรรมอีกต่อไปสิ่งนี้จะเอาชนะจุดประสงค์ของการใช้คลาสนามธรรมตั้งแต่แรก ... จะแก้ปัญหานี้ได้อย่างไร?
Darius

1
@ ti034 ฉันไม่พบวิธีแก้ปัญหาใด ๆ ดังนั้นฉันแค่ทำให้ฟังก์ชันนามธรรมที่คาดคะเนจาก middleClass มีค่าเริ่มต้นบางอย่างที่สามารถเตือนให้ฉันลบล้างได้โดยไม่ต้องให้คอมไพเลอร์โยนข้อผิดพลาด ตัวอย่างเช่นหากวิธีนามธรรมที่คาดคะเนคือการส่งคืนชื่อของเพจฉันจะส่งคืนสตริง "Please change the title"
Darius

74

@smelch มีวิธีแก้ปัญหาที่ดีกว่าโดยไม่ต้องสร้างตัวควบคุมตรงกลางแม้แต่การดีบัก

สิ่งที่เราต้องการ

ก่อนอื่นให้กำหนดคลาสสุดท้ายและคลาสนามธรรมพื้นฐาน

public class MyControl : AbstractControl
...
public abstract class AbstractControl : UserControl // Also works for Form
...

ตอนนี้สิ่งที่เราจำเป็นที่จะต้องเป็นผู้ให้คำอธิบาย

public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
{
    public AbstractControlDescriptionProvider()
        : base(TypeDescriptor.GetProvider(typeof(TAbstract)))
    {
    }

    public override Type GetReflectionType(Type objectType, object instance)
    {
        if (objectType == typeof(TAbstract))
            return typeof(TBase);

        return base.GetReflectionType(objectType, instance);
    }

    public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
    {
        if (objectType == typeof(TAbstract))
            objectType = typeof(TBase);

        return base.CreateInstance(provider, objectType, argTypes, args);
    }
}

ในที่สุดเราก็ใช้แอตทริบิวต์ TypeDescriptionProvider กับตัวควบคุม Abastract

[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<AbstractControl, UserControl>))]
public abstract class AbstractControl : UserControl
...

และนั่นแหล่ะ ไม่จำเป็นต้องมีการควบคุมระดับกลาง

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

* แก้ไข * จำเป็นต้องมีสิ่งต่อไปนี้ใน app.config

<appSettings>
    <add key="EnableOptimizedDesignerReloading" value="false" />
</appSettings>

ขอบคุณ @ user3057544 สำหรับข้อเสนอแนะ



1
สิ่งนี้ได้ผลเช่นกันสำหรับฉันที่ฉันใช้ CF 3.5 ไม่มีTypeDescriptionProvider
Adrian Botor

4
ไม่สามารถใช้งานได้ใน VS 2010 แม้ว่า smelch จะได้ผล ใครทราบสาเหตุ?
RobC

5
@RobC Designer ไม่พอใจด้วยเหตุผลบางอย่าง ฉันพบว่าหลังจากใช้การแก้ไขนี้แล้วฉันต้องทำความสะอาดโซลูชันปิดและเปิดใช้ VS2010 ใหม่และสร้างใหม่ จากนั้นให้ฉันออกแบบคลาสย่อย
Oblivious Sage

3
เป็นที่น่าสังเกตว่าเนื่องจากฟิกซ์นี้แทนที่อินสแตนซ์ของคลาสพื้นฐานสำหรับคลาสนามธรรมองค์ประกอบภาพที่เพิ่มในตัวออกแบบสำหรับคลาสนามธรรมจะไม่พร้อมใช้งานเมื่อออกแบบคลาสย่อย
Oblivious Sage

1
สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่ก่อนอื่นฉันต้องรีสตาร์ท VS 2013 หลังจากสร้างโครงการ @ObliviousSage - ขอบคุณสำหรับการแก้ไข; ในกรณีปัจจุบันของฉันอย่างน้อยนี่ไม่ใช่ปัญหา แต่ก็ยังเป็นสิ่งที่ดีที่ต้องระวัง
InteXX

10

@Smelch ขอบคุณสำหรับคำตอบที่เป็นประโยชน์ขณะที่ฉันพบปัญหาเดียวกันเมื่อเร็ว ๆ นี้

ต่อไปนี้เป็นการเปลี่ยนแปลงเล็กน้อยในโพสต์ของคุณเพื่อป้องกันคำเตือนการคอมไพล์ (โดยใส่คลาสพื้นฐาน#if DEBUGไว้ในคำสั่งก่อนโปรเซสเซอร์):

public class Form1
#if DEBUG  
 : MiddleClass 
#else  
 : BaseForm 
#endif 

5

ฉันมีปัญหาที่คล้ายกัน แต่พบวิธีที่จะ refactor สิ่งต่าง ๆ เพื่อใช้อินเทอร์เฟซแทนคลาสฐานนามธรรม:

interface Base {....}

public class MyUserControl<T> : UserControl, Base
     where T : /constraint/
{ ... }

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


1
คุณช่วยให้ตัวอย่างโค้ดที่สมบูรณ์กว่านี้ได้ไหม ฉันกำลังพยายามทำความเข้าใจการออกแบบของคุณให้ดีขึ้นและฉันจะแปลเป็น VB ด้วย ขอบคุณ.
InteXX

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

3

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

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


3

ฉันมีเคล็ดลับสำหรับคนที่บอกว่าTypeDescriptionProviderโดย Juan Carlos Diaz ใช้งานไม่ได้และไม่ชอบการรวบรวมแบบมีเงื่อนไขเช่นกัน:

ก่อนอื่นคุณอาจต้องรีสตาร์ท Visual Studioเพื่อให้การเปลี่ยนแปลงในโค้ดของคุณทำงานในตัวออกแบบฟอร์ม (ฉันต้องสร้างใหม่อย่างง่ายไม่ได้ผล - หรือไม่ทุกครั้ง)

ฉันจะนำเสนอวิธีแก้ปัญหานี้สำหรับกรณีของแบบฟอร์มฐานนามธรรม สมมติว่าคุณมีBaseFormชั้นเรียนและคุณต้องการให้รูปแบบใด ๆ จากพื้นฐานนั้นสามารถออกแบบได้ (สิ่งนี้จะเป็นForm1) สิ่งTypeDescriptionProviderที่ Juan Carlos Diaz นำเสนอก็ไม่ได้ผลสำหรับฉันเช่นกัน นี่คือวิธีที่ฉันทำให้มันใช้งานได้โดยการเข้าร่วมกับโซลูชัน MiddleClass (โดย smelch) แต่ไม่มีการ#if DEBUGรวบรวมตามเงื่อนไขและมีการแก้ไขบางอย่าง:

[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<BaseForm, BaseFormMiddle2>))]   // BaseFormMiddle2 explained below
public abstract class BaseForm : Form
{
    public BaseForm()
    {
        InitializeComponent();
    }

    public abstract void SomeAbstractMethod();
}


public class Form1 : BaseForm   // Form1 is the form to be designed. As you see it's clean and you do NOTHING special here (only the the normal abstract method(s) implementation!). The developer of such form(s) doesn't have to know anything about the abstract base form problem. He just writes his form as usual.
{
    public Form1()
    {
        InitializeComponent();
    }

    public override void SomeAbstractMethod()
    {
        // implementation of BaseForm's abstract method
    }
}

สังเกตแอตทริบิวต์บนคลาส BaseForm จากนั้นคุณก็ต้องประกาศTypeDescriptionProviderและสองชั้นกลางแต่ไม่ต้องกังวลพวกเขาจะมองไม่เห็นและไม่เกี่ยวข้องสำหรับนักพัฒนาของ Form1 อันแรกใช้สมาชิกนามธรรม (และทำให้คลาสฐานไม่ใช่นามธรรม) อันที่สองว่างเปล่า - จำเป็นสำหรับผู้ออกแบบฟอร์ม VS จึงจะทำงานได้ จากนั้นคุณกำหนดสองชั้นกลางไปของTypeDescriptionProvider ไม่มีการรวบรวมตามเงื่อนไขBaseForm

ฉันมีปัญหาอีกสองอย่าง:

  • ปัญหาที่ 1:หลังจากเปลี่ยน Form1 ในตัวออกแบบ (หรือรหัสบางตัว) ก็แสดงข้อผิดพลาดอีกครั้ง (เมื่อพยายามเปิดในตัวออกแบบอีกครั้ง)
  • ปัญหาที่ 2:ตัวควบคุมของ BaseForm ถูกวางอย่างไม่ถูกต้องเมื่อขนาดของ Form1 ถูกเปลี่ยนในตัวออกแบบและฟอร์มถูกปิดและเปิดใหม่อีกครั้งในตัวออกแบบฟอร์ม

ปัญหาแรก (คุณอาจไม่มีเพราะเป็นสิ่งที่หลอกหลอนฉันในโครงการของฉันไม่กี่แห่งและมักจะสร้างข้อยกเว้น "ไม่สามารถแปลงประเภท X เป็นประเภท X") ฉันแก้ไขTypeDescriptionProviderโดยการเปรียบเทียบชื่อประเภท (FullName) แทนที่จะเปรียบเทียบประเภท (ดูด้านล่าง)

ปัญหาที่สอง ฉันไม่รู้จริงๆว่าทำไมตัวควบคุมของแบบฟอร์มพื้นฐานจึงไม่สามารถออกแบบได้ในคลาส Form1 และตำแหน่งของพวกเขาจะหายไปหลังจากปรับขนาด แต่ฉันได้แก้ไขแล้ว (ไม่ใช่วิธีแก้ปัญหาที่ดี - ถ้าคุณรู้ดีกว่านี้โปรดเขียน) ฉันเพิ่งย้ายปุ่มของ BaseForm ด้วยตนเอง (ซึ่งควรอยู่ที่มุมล่างขวา) ไปยังตำแหน่งที่ถูกต้องในวิธีการที่เรียกใช้แบบอะซิงโครนัสจากเหตุการณ์ Load ของ BaseForm: BeginInvoke(new Action(CorrectLayout));คลาสฐานของฉันมีเพียงปุ่ม "ตกลง" และ "ยกเลิก" ดังนั้น กรณีเป็นเรื่องง่าย

class BaseFormMiddle1 : BaseForm
{
    protected BaseFormMiddle1()
    {
    }

    public override void SomeAbstractMethod()
    {
        throw new NotImplementedException();  // this method will never be called in design mode anyway
    }
}


class BaseFormMiddle2 : BaseFormMiddle1  // empty class, just to make the VS designer working
{
}

และที่นี่คุณมีเวอร์ชันแก้ไขเล็กน้อยของTypeDescriptionProvider:

public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
{
    public AbstractControlDescriptionProvider()
        : base(TypeDescriptor.GetProvider(typeof(TAbstract)))
    {
    }

    public override Type GetReflectionType(Type objectType, object instance)
    {
        if (objectType.FullName == typeof(TAbstract).FullName)  // corrected condition here (original condition was incorrectly giving false in my case sometimes)
            return typeof(TBase);

        return base.GetReflectionType(objectType, instance);
    }

    public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
    {
        if (objectType.FullName == typeof(TAbstract).FullName)  // corrected condition here (original condition was incorrectly giving false in my case sometimes)
            objectType = typeof(TBase);

        return base.CreateInstance(provider, objectType, argTypes, args);
    }
}

เท่านี้เอง!

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

อีกหนึ่งเคล็ดลับ:

หากนักออกแบบยังคงปฏิเสธที่จะทำงานให้คุณด้วยเหตุผลบางประการคุณสามารถทำเคล็ดลับง่ายๆในการเปลี่ยนpublic class Form1 : BaseFormto public class Form1 : BaseFormMiddle1(หรือBaseFormMiddle2) ในไฟล์โค้ดแก้ไขได้ใน VS form designer แล้วเปลี่ยนกลับอีกครั้ง ฉันชอบเคล็ดลับนี้มากกว่ารวบรวมเงื่อนไขเพราะมันมีโอกาสน้อยที่จะลืมและปล่อยรุ่นที่ไม่ถูกต้อง


1
สิ่งนี้ช่วยแก้ปัญหาที่ฉันพบกับโซลูชันของ Juan ใน VS 2013; ในการรีสตาร์ท VS การควบคุมจะโหลดอย่างสม่ำเสมอในขณะนี้
Luke Merrett

3

ฉันมีเคล็ดลับสำหรับโซลูชัน Juan Carlos Diaz มันใช้งานได้ดีสำหรับฉัน แต่ก็มีปัญหากับมัน เมื่อฉันเริ่ม VS และเข้าสู่นักออกแบบทุกอย่างทำงานได้ดี แต่หลังจากรันโซลูชันแล้วให้หยุดและออกจากนั้นลองป้อนตัวออกแบบข้อยกเว้นจะปรากฏขึ้นอีกครั้งและอีกครั้งจนกว่าจะรีสตาร์ท VS แต่ฉันพบวิธีแก้ปัญหา - สิ่งที่ต้องทำคือเพิ่มด้านล่างลงใน app.config ของคุณ

  <appSettings>
   <add key="EnableOptimizedDesignerReloading" value="false" />
  </appSettings>

2

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

public class DataForm : Form {
    protected virtual void displayFields() {}
}

public partial class Form1 : DataForm {
    protected override void displayFields() { /* Do the stuff needed for Form1. */ }
    ...
}

public partial class Form2 : DataForm {
    protected override void displayFields() { /* Do the stuff needed for Form2. */ }
    ...
}

/* Do this for all classes that inherit from DataForm. */

เนื่องจากDataFormควรจะเป็นคลาสนามธรรมกับสมาชิกนามธรรมdisplayFieldsฉันจึง "ปลอม" พฤติกรรมนี้กับสมาชิกเสมือนเพื่อหลีกเลี่ยงสิ่งที่เป็นนามธรรม นักออกแบบไม่บ่นอีกต่อไปและทุกอย่างทำงานได้ดีสำหรับฉัน

มันเป็นวิธีแก้ปัญหาที่อ่านได้มากขึ้น แต่ในเมื่อมันไม่ได้เป็นนามธรรมฉันมีเพื่อให้แน่ใจว่าทุกชั้นเรียนของเด็กมีการดำเนินงานของพวกเขาDataForm displayFieldsดังนั้นควรระมัดระวังในการใช้เทคนิคนี้


นี่คือสิ่งที่ฉันไปด้วย ฉันเพิ่งโยน NotImplementedException ในคลาสพื้นฐานเพื่อให้ข้อผิดพลาดชัดเจนหากลืม
Shaun Rowan

1

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

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


น่าเสียดาย แต่นั่นเป็นวิธีที่เสร็จสิ้น หวังว่าจะได้วิธีที่ถูกต้องในการทำเช่นนี้
Oliver Friedrich

มีวิธีที่ดีกว่าดูคำตอบของ Smelch
Allen Rice

-1

คุณสามารถคอมไพล์ตามเงื่อนไขในabstractคีย์เวิร์ดโดยไม่ต้องแทรกคลาสแยก:

#if DEBUG
  // Visual Studio 2008 designer complains when a form inherits from an 
  // abstract base class
  public class BaseForm: Form {
#else
  // For production do it the *RIGHT* way.
  public abstract class BaseForm: Form {
#endif

    // Body of BaseForm goes here
  }

งานนี้มีเงื่อนไขว่าBaseFormไม่มีเมธอดนามธรรม ( abstractคีย์เวิร์ดจึงป้องกันการสร้างอินสแตนซ์รันไทม์ของคลาสเท่านั้น)

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