2010-06-28 10 views
5

अस्पष्ट शीर्षक के लिए खेद है, लेकिन मुझे यकीन नहीं था कि इसे एक वाक्यांश में सारांशित कैसे किया जाए। मेरे पास बहुत अनावश्यक सी # कोड के साथ एक स्थिति है, और यह वास्तव में विरासत या जेनेरिक की कुछ संपत्ति का उपयोग करके किसी तरह की चालाक चाल की तरह दिखता है। हालांकि, मैं एक बहुत अनुभवी प्रोग्रामर नहीं हूं (विशेष रूप से सी # के साथ) और बस समाधान को काफी नहीं देख सकता।विरासत या जेनेरिक के माध्यम से अनावश्यक कोड से छुटकारा पाने में परेशानी होने के कारण

स्थिति, सरलीकृत रूप में, इस तरह कुछ दिखता है। मेरे पास कक्षाओं का एक गुच्छा है जो सभी एक प्रकार से प्राप्त होते हैं।

public class Foo : SuperFoo 
{ 
    ... 
    public Foo SomeMethod() { ... } 
} 
public class Bar : SuperFoo 
{ 
    ... 
    public Bar SomeMethod() { ... } 
} 
public class Baz : SuperFoo 
{ 
    ... 
    public Baz SomeMethod() { ... } 
} 
...  
public class SuperFoo 
{ 
    ... 
} 

समस्या आता है जब इन वस्तुओं के संग्रह संसाधित करने की आवश्यकता। मेरा पहला-ड्राफ्ट समाधान (बुरा) इस तरह दिखता है:

public void SomeEventHasHappened(...) 
{ 
    ProcessFoos(); 
    ProcessBars(); 
    ProcessBazes(); 
    ... 
} 

public void ProcessFoos() 
{ 
    ... 
    foreach (var foo in fooList) 
    { 
      ... 
      foo.SomeMethod(); 
    } 
} 
public void ProcessBars() 
{ 
    ... 
    foreach (var bar in barList) 
    { 
      ... 
      bar.SomeMethod(); 
    } 
} 

... और इतने पर। समस्या यह है कि मूल रूप से ProcessX विधियों में से सभी कोड समान वस्तुओं के प्रकार के अलावा समान होते हैं। स्पष्ट कारणों से इन सभी को एक विधि में समेकित करना अच्छा होगा।

मेरा पहला विचार केवल एक सामान्य प्रक्रिया() विधि बनाना था जिसने पैरामीटर के रूप में List<SuperFoo> लिया और बस वहां से आगे बढ़ें। समस्या यह है कि एक सामान्य सुपरफू में कोई विधि नहीं है(), और इसमें कोई नहीं हो सकता है क्योंकि प्रत्येक बच्चे वर्ग 'SomeMethod() में एक अलग रिटर्न प्रकार होता है, इसलिए ओवरराइड काम नहीं करते हैं।

+0

मैंने कोड देखा है जहां 'ऑब्जेक्ट' लौटाया गया है, और फिर उपयुक्त प्रकार पर डाला गया है। –

+0

हालांकि समस्या को हल करने के रूप में मैंने इसे यहां प्रस्तुत किया है, मुझे स्पष्ट करना चाहिए ... मैं पसंद करता हूं कि 'SomeMethod()' सामान्य 'ऑब्जेक्ट' वापस न करें, क्योंकि 'SomeMethod()' को भी कॉल किया जाता है कोड के इस हिस्से के अलावा कई अन्य स्थानों, और उन सभी अन्य स्थानों में कास्टिंग की आवश्यकता होगी। फिर भी सुझाव के लिए धन्यवाद। – jloubert

उत्तर

2

मैं आमतौर पर एक इंटरफ़ेस जोड़ता हूं जो आधार प्रकारों पर चल रहा है।

interface ISuperFoo 
{ 
    public ISuperFoo SomeMethod() { ... } 
} 

public class Foo : SuperFoo, ISuperFoo 
{ 
    // concrete implementation 
    public Foo SomeMethod() { ... } 

    // method for generic use, call by base type 
    public ISuperFoo ISuperFoo.SomeMethod() 
    { 
     return SomeMethod(); 
    } 
} 

public void Processs() 
{ 
    ... 
    foreach (var iSuperFoo in list) 
    { 
      ... 
      iSuperFoo.SomeMethod(); 
    } 
} 

बेशक यह निर्भर करता है कि आप किस परिणाम का उपयोग कर रहे हैं।

कभी-कभी आप जेनिक्स का उपयोग करके इसे आसान बना सकते हैं, लेकिन आप भी गड़बड़ी में समाप्त हो सकते हैं। कभी-कभी कहीं कहीं कम करना आसान होता है। बेशक, जब भी आप इसे बर्दाश्त कर सकते हैं, तो आप इससे बचने की कोशिश करते हैं।

+0

यह बहुत अच्छा है, और संभवतः मुझे कुछ सोचना चाहिए था! जवाब के लिए धन्यवाद। – jloubert

2

यहां एक उदाहरण दिया गया है कि यह जेनेरिक का उपयोग करके कैसे काम कर सकता है और सुपरफू को एक अमूर्त वर्ग बना सकता है।

public interface ISuperFoo 
{ 
    ... 
} 

public abstract class SuperFoo<T> where T : ISuperFoo 
{ 
    public abstract T SomeMethod(); 
} 

public class BazReturn : ISuperFoo 
{ 
    ... 
} 

public class Baz: SuperFoo<BazReturn> 
{ 
    public override BazReturn SomeMethod() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class BarReturn : ISuperFoo 
{ 
    ... 
} 

public class Bar : SuperFoo<BarReturn> 
{ 
    public override BarReturn SomeMethod() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static class EventHandler 
{ 
    public static void SomeEventHasHappened(List<SuperFoo<ISuperFoo>> list) 
    { 
     foreach (SuperFoo<ISuperFoo> item in list) 
     { 
      ISuperFoo result = item.SomeMethod(); 
     } 
    } 
} 

आप यदि आवश्यक हो तो एक ठोस वर्ग के साथ ISuperFoo इंटरफेस की जगह सकता है, लेकिन उसके बाद आप वापसी मान किस तरह के प्रयोजन धरा कास्ट करने के लिए होगा।

public abstract class SuperFoo<T> 
{ 
    public abstract T SomeMethod(); 
} 

public class Foo : SuperFoo<int> 
{ 
    public override int SomeMethod() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static class EventHandler 
{ 
    public static void SomeEventHasHappened(List<SuperFoo<int>> list) 
    { 
     foreach (SuperFoo<int> item in list) 
     { 
      item.SomeMethod(); 
     } 
    } 
} 
+0

प्रतिक्रिया के लिए धन्यवाद। लेकिन मैं आपके उत्तर के पहले भाग में FooReturn और Foo कक्षाओं द्वारा थोड़ा उलझन में हूं। अगर मैं इसे सही ढंग से समझता हूं, तो ऐसा लगता है कि Foo's SomeMethod() का एक उदाहरण Foo ऑब्जेक्ट के बजाय FooReturn ऑब्जेक्ट लौटाएगा। इसलिए, फू में होने वाले सभी अन्य कोड अब FooReturn में होना चाहिए, जबकि Foo को केवल कुछ विधि() को शामिल करने की आवश्यकता है। यदि यह वास्तव में मामला है, तो यह किसी अन्य स्थान पर यह ब्रेक कोड नहीं होगा जिसमें 'Foo fooObject = anotherFooObject.SomeMethod(); '? – jloubert

+0

कुछ विधि के रिटर्न प्रकार को हमेशा ISUPerFoo लौटने के रूप में माना जाना चाहिए। आप देखेंगे कि अमूर्त सुपरफू के जेनेरिक varialbe टी को ISuperFoo का विस्तार करना होगा।यही वह आवश्यक रिटर्न प्रकार देता है जो आवश्यक है। मैंने अपने कोड में एक बार उदाहरण जोड़ा है जो उम्मीदपूर्वक स्पष्ट करेगा। – sgriffinusa

+0

मैंने फू टू बज़ से बाल वर्ग का नाम बदल दिया है जो आशा करता है कि इंटरफ़ेस, सार और विस्तारित प्रकारों के बीच अंतर को और स्पष्ट किया जाएगा। – sgriffinusa

संबंधित मुद्दे