2012-04-11 11 views
5

संभव डुप्लिकेट:
C# - Is there a better alternative than this to ‘switch on type’?सबसे अच्छा तरीका है प्रकार के आधार पर

पर विचार क्लासिक:

class Widget { } 
class RedWidget : Widget { } 
class BlueWidget : Widget { } 

अधिकांश भाग के लिए, मेरे यूआई में, मैं सभी Widget एस का इलाज कर सकते हैं। हालांकि, मामूली मतभेद हैं, जिन्हें मुझे if या switch के माध्यम से करने की आवश्यकता है।

संभावित दृष्टिकोण:

Enum संकेतक - निर्माता द्वारा निर्धारित

enum WidgetVariety { Red, Blue } 

class Widget { 
    public WidgetVariety Variety { get; protected set; } 
} 

class RedWidget : Widget { 
    public RedWidget() { 
     Variety = Red; 
    } 
} 

// Likewise for BlueWidget... 

switch (mywidget.Variety) { 
case WidgetVariety.Red: 
    // Red specific GUI stuff 

case WidgetVariety.Blue: 
    // Blue specific GUI stuff 
} 

उपयोग is

Widget w = ...; 
if (w is RedWidget) { 
    (RedWidget)w ... 
} 
else if (w is BlueWidget) { 
    (BlueWidget)w ... 
} 

कारण मैं इस का सहारा लिया गया है 1) के अधिकांश कोड पहले से ही कुछ हद तक लिखा है, लेकिन बहुत उलझन में है। 2) कोड का 9 0% समान है - मूल रूप से ग्रिड व्यू में केवल एक कॉलम को प्रकार के आधार पर अलग-अलग संभाला जाना चाहिए।

आप किसकी सिफारिश करेंगे? (या किसी को भी एक बेहतर समाधान है?)


संपादित मैं जानता हूँ कि मैं शायद आगंतुक पैटर्न की सिफारिश की हो जाएगा, लेकिन यह केवल इस मामले में विरल, मामूली अंतर के लिए जटिल लगता है।

संपादित करें 2 तो एक विशेष अंतर मुझे हार्ड टाइम सॉर्टिंग करना मुश्किल था, यह कॉलम दो प्रकार के बीच अलग है। एक मामले में, यह bool मान पुनर्प्राप्त करता है, और ग्रिड सेल को असाइन करता है। दूसरे मामले में, यह एक स्ट्रिंग मान मिलता है।

मैं इस मामले में लगता है, यह स्पष्ट है कि मैं निर्धारित कर सकते हैं होना चाहिए:

public object virtual GetColumn4Data(); 

public override GetColumn4Data() { return m_boolval; } 

public override GetColumn4Data() { return m_mystring; } 

यह object के उपयोग के कारण शुरू में मेरे लिए गलत महसूस किया है,। हालांकि, उस संपत्ति का प्रकार है जिसे मैं सेल में असाइन कर रहा हूं, इसलिए बेशक यह समझ में आता है!

कार्यालय आज ऐसा लगता है पर बहुत लंबे ...

+3

ऐसा लगता है कि आप जो कह रहे हैं वह है: चूंकि अधिकांश कोड पहले से ही खराब लिखा गया है, इसलिए आपको अधिक बदसूरत हार्ड-टू-कोड कोड लिखकर प्रवृत्ति को जारी रखने की आवश्यकता है। –

+0

यदि आपके उप-वर्गों में एक प्रकार है जो उनके बीच भिन्न होता है, तो शायद बेस क्लास सामान्य होना चाहिए। फिर यह 'सार्वजनिक वर्चुअल टी GetColumn4Data() बन जाता है; ... सार्वजनिक ओवरराइड बूल GetColumn4Data() {वापसी m_boolval; } ... सार्वजनिक ओवरराइड स्ट्रिंग GetColumn4Data() {वापसी m_mystring; } ' –

+0

@Sahuagin - कृपया उत्तर के लिए बड़े कोड स्निपेट सहेजें। टिप्पणियाँ उन्हें न्याय नहीं करते हैं। –

उत्तर

9

एक और संभावना है। आभासी प्रेषण का उपयोग करें:

class Widget 
{ 
    public virtual void GuiStuff() { } 
} 
class RedWidget : Widget 
{ 
    public override void GuiStuff() 
    { 
     //... red-specific GUI stuff 
     base.GuiStuff(); 
    } 
} 
class BlueWidget : Widget 
{ 
    public override void GuiStuff() 
    { 
     //... blue-specific GUI stuff 
     base.GuiStuff(); 
    } 
} 
+0

बेशक .... मेरा संपादन 2 देखें :-) –

5

Subtype polymorphism, सबसे अच्छा समाधान है चेकों के इस प्रकार से परहेज मुख्य कारणों OO बनाया गया था से एक है।

Widget में एक विधि DoSomething() (शायद सार) हो सकती है और फिर RedWidget और BlueWidget इसे ओवरराइड कर देगी।

भी देखें मार्टिन फाउलर की Replace Conditional with Polymorphism:

देखा: आप एक सशर्त है कि एक वस्तु के प्रकार के आधार पर अलग व्यवहार चुनता है।

रिएक्टर: सशर्त के प्रत्येक चरण को सबक्लास में ओवरराइडिंग विधि में ले जाएं। मूल विधि सार बनाओ।

+2

मैं इस विचार से असहमत हूं कि [इस तरह का] बहुरूपता "ओओ क्यों बनाया गया था"; यह कुछ "ओओ भाषाओं" के * प्रभाव * से अधिक है। हालांकि, अन्य बिट्स के लिए +1। (उबाऊ - और खतरनाक से अधिक प्रकार के बहुरूपता हैं! - उदाहरण के लिए सी #/जावा में एकल-प्रेषण उपप्रकार पाए जाते हैं।) –

+0

@pst मैं आपका बिंदु देखता हूं, दिलचस्प विषय – jorgehmv

0

संपादन # 2 के तहत अपने प्रश्न के लिए, आप उप-वर्गों के बीच प्रकार को अलग करने के लिए एक सामान्य वर्ग का उपयोग कर सकते हैं, हालांकि यह आपके डिजाइन के आधार पर आपके लिए काम कर सकता है या नहीं। यह शायद अन्य कठिन डिजाइन निर्णयों का नेतृत्व करेगा।

असहज उदाहरण:

internal abstract class BaseClass 
{ 
    protected object mValue; // could also be defined as a T in BaseClass<T> 

    public object GetColumn4Data { get { return mValue; } } 
} 

// this is a group of classes with varying type 
internal abstract class BaseClass<T> : BaseClass 
{ 
    public T GetTypedColumn4Data 
    { 
     get { return (T)mValue; } 
     set { mValue = value; } 
    } 
} 

// these are not really necessary if you don't plan to extend them further 
// in that case, you would mark BaseClass<T> sealed instead of abstract 
internal sealed class BoolSubClass : BaseClass<bool> 
{ 
    // no override necessary so far 
} 

internal sealed class StringSubClass : BaseClass<string> 
{ 
    // no override necessary so far 
} 

लेकिन ध्यान दे, कि तुम सच में एक भी संदर्भ प्रकार कुछ संपत्ति या विधि पर एक अलग वापसी प्रकार होगा कि नहीं मिल सकता है। एक BaseClass संदर्भ सबसे अच्छा सामान्य प्रकार (जैसे object) पर वापस आ जाएगा।

+0

दुर्भाग्य से यह यहां काम नहीं करेगा। यह विशेष प्रकार का अंतर केवल कई छोटे, लेकिन महत्वपूर्ण अंतरों में से एक है। हालांकि यह एकमात्र अंतर था, मैं इस दृष्टिकोण से सहमत हूं। –