2012-05-04 11 views
7

मैं एक पैरामीटर के रूप में एक सामान्य प्रकार के साथ एक प्रतिनिधि है। इसलिए, मैंने किया:सी # सामान्य घटनाक्रम

public event UpdatedPropertyDelegate<T> UpdatedProperty; 

हालांकि, संकलक इसे पसंद नहीं करता है। मुझे समझ में नहीं आता कि टी को यहां क्यों निर्दिष्ट किया जाना है। निश्चित रूप से यह निर्दिष्ट है कि जब मैं घटना को आग लगाता हूं, यानी

if (UpdatedProperty != null) 
{ 
    UpdatedProperty(this, readProperty, 
     ReplicableObjectBin.GetObjectByID(readProperty.OwnerID)); 
} 

तो, क्या मैं कुछ आसान गलत कर रहा हूं? या यह समझने की एक बड़ी विफलता है?

धन्यवाद।

+3

संकलक एक अज्ञात जेनेरिक प्रकार के साथ एक संपत्ति को स्वीकार नहीं करेगा जिसे रनटाइम तक नहीं जाना जा सकता है। – BoltClock

+0

आप इसका क्या मतलब चाहते हैं? – SLaks

+0

मैं घटना में एक सामान्य पैरामीटर पास करना चाहता हूं। बस इतना ही। निश्चित रूप से अगर मुझे पता था कि टाइप टी किस प्रकार संकलित समय पर होगा, तो मुझे जेनिक्स का उपयोग करने की आवश्यकता नहीं होगी? – Xenoprimate

उत्तर

7

यह है कि तुम क्या जरूरत है एक अंतरफलक प्रकार, बल्कि एक प्रतिनिधि से है की तरह लगता है की जरूरत है। इंटरफ़ेस विधियां खुले सामान्य प्रकार (जो आप बाद में हैं) स्वीकार कर सकते हैं, भले ही प्रतिनिधि नहीं कर सकते हैं। उदाहरण के लिए, एक तरह कुछ निर्धारित कर सकते हैं:

interface ActOnConstrainedThing<CT1,CT2> 
{ 
    void Act<MainType>(MainType param) where MainType: CT1,CT2; 
} 

CT1 और CT2 के कार्यान्वयन एक आम आधार प्रकार जो भी CT1 और CT2, लागू करता है का हिस्सा नहीं है यहां तक ​​कि अगर Act के एक कार्यान्वयन एक के रूप में अपनी पारित कर दिया-इन पैरामीटर का उपयोग कर सकते हैं CT1 या CT2 टाइपकास्ट के बिना, और इसे दिनचर्या में भी पास कर सकता है जो CT1 और CT2 बाधाओं के साथ एक सामान्य पैरामीटर की अपेक्षा करता है। प्रतिनिधियों के साथ ऐसी चीज संभव नहीं होगी।

ध्यान दें कि प्रतिनिधियों के बजाय इंटरफेस का उपयोग करना मतलब है कि कोई सामान्य "ईवेंट" तंत्र और वाक्यविन्यास का उपयोग नहीं कर सकता है। इसके बजाए, ऑब्जेक्ट प्रकाशक होने वाली ऑब्जेक्ट को वांछित इंटरफ़ेस को लागू करने वाले ऑब्जेक्ट उदाहरणों की एक सूची बनाए रखना चाहिए (उदा। List<ActOnConstrainedThing<IThis,IThat>>), और उस सूची के उदाहरणों का अनुमान लगाएं (शायद foreeach का उपयोग कर)।

 
List<IActOnConstrainedThing<IThis,IThat>> _ActOnThingSubscribers; 

void ActOnThings<T>(T param) where T:IThis,IThat 
{ 
    foreach(var thing in _ActOnThingSubscribers) 
    { 
    thing.Act<T>(param); 
    } 
} 

संपादित करें/परिशिष्ट

जगह मैं कहाँ कार्यरत इस पैटर्न भी कुछ अन्य सामान जो ज़रूरत से ज़्यादा सवाल है, जो मेरी व्याख्या द्वारा कैसे एक पूछ रहा था के लिए प्रासंगिक नहीं मालूम था था: उदाहरण के लिए एक ओपन टाइप पैरामीटर के साथ एक प्रतिनिधि (या समतुल्य) हो सकता है, ताकि प्रतिनिधि-समकक्ष का आह्वान करने वाला ऑब्जेक्ट ऑब्जेक्टको बिना किसी जानकारी के प्रतिनिधि को आपूर्ति करने के लिए टाइप पैरामीटर की आपूर्ति कर सके। अधिकांश मामलों में जहां इस उपयोगी है सामान्य की कमी शामिल है, लेकिन यह है कि जाहिरा तौर पर परिचय दे रहा था भ्रम के बाद से, यहां एक उदाहरण है कि ऐसा नहीं करता है:

 
interface IShuffleFiveThings 
{ 
    void Shuffle<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5); 
} 
List<IShuffleFiveThings _ShuffleSubscribers; 

void ApplyShuffles<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5) 
{ 
    foreach(var shuffler in _ShuffleSubscribers) 
    { 
    thing.Shuffle(ref p1, ref p2, ref p3, ref p4, ref p5); 
    } 
} 

IShuffleFiveThings.Shuffle<T> विधि ref द्वारा पांच पैरामीटर लेता है और (सबसे अधिक संभावना permutes उनके साथ कुछ करता है उन्हें कुछ फैशन में; शायद उन्हें यादृच्छिक रूप से अनुमति दे रहा है, या शायद कुछ यादृच्छिक रूप से दूसरों को छोड़कर उन्हें अनुमति दे रहा है।अगर किसी की सूची IShuffleFiveThings है, तो उस सूची में मौजूद चीजों को मुक्केबाजी या प्रतिबिंब के बिना कुशलता से उपयोग किया जा सकता है, किसी भी प्रकार की चीज (वर्ग प्रकार और मूल्य प्रकार दोनों सहित) में हेरफेर करने के लिए।

 
delegate void ActOn5RefParameters(ref p1, ref p2, ref p3, ref p4, ref p5); 

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

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

+0

यह दिलचस्प है। ओपी प्रश्न में, क्या यह इंटरफ़ेस उस प्रकार से कार्यान्वित किया जाएगा जो उसकी घटना को परिभाषित कर रहा था या क्या यह घटना में पारित होने वाले प्रकार से लागू किया जाएगा? असल में, ओपी समाधान में इसका उपयोग कैसे किया जाएगा? – Jim

+0

@Jim: ऊपर संपादन देखें। कोई घटनाओं का उपयोग नहीं कर सकता है, लेकिन कोई इंटरफेस के साथ समान प्रभाव प्राप्त कर सकता है।'IObservable' /' IObserver' द्वारा उपयोग किया जाने वाला पैटर्न घटनाओं का उपयोग करने का एक अच्छा विकल्प हो सकता है। – supercat

+0

@supercate - ठीक है मुझे यहां पर्यवेक्षक पैटर्न मिलता है लेकिन क्या संलग्न प्रकार को अभी भी आईटीआईएस, आईटीएचटी प्रकार पैरामीटर को परिभाषित नहीं करना होगा या यह स्वयं भी इन प्रकार के पैरामीटर निर्दिष्ट करेगा? – Jim

4

आप संक्षेप में उस प्रतिनिधि का उदाहरण बना रहे हैं। उदाहरणों को उनके सामान्य प्रकार परिभाषित करने की आवश्यकता है।

अपने प्रतिनिधि की परिभाषा टी शामिल कर सकते हैं, लेकिन अपने उदाहरण परिभाषित करने के लिए जो टी

+2

या एक सामान्य वर्ग में रहें जो 'टी' – payo

+0

परिभाषित करता है, तो, किसी घटना में जेनेरिक पैरामीटर को पास करने का कोई तरीका है (संकलित समय पर टाइप टी निर्दिष्ट किए बिना, जो मुझे सामान्य के बिंदु को दूर करने लगता है)? – Xenoprimate

+0

सच है, उस स्थिति में टी को कक्षा के उदाहरण द्वारा परिभाषित किया गया है, इसलिए प्रतिनिधि उदाहरण भी परिभाषित किया गया है, जो मैंने जो कहा है उसके साथ है। –

3

इस उदाहरण को देखते हुए:

public delegate void FooDelegate<T>(T value); 

public class FooContainer 
{ 
    public event FooDelegate<T> FooEvent; 
} 

संकलक के रूप में अपने उदाहरण में FooEvent घोषणा पसंद नहीं करता क्योंकि T परिभाषित नहीं है। हालांकि,

public delegate void FooDelegate<T>(T value); 

public class FooContainer<T> 
{ 
    public event FooDelegate<T> FooEvent; 
} 

को FooContainer बदल रहा और अब संकलक के साथ इस वजह से जो कोई भी FooContainer के उदाहरण बनाता है अब तो

FooContainer<string> fooContainer = new FooFooContainer<string>(); 

तरह प्रकार टी निर्दिष्ट करने के लिए लेकिन अगर आप भी एक के लिए T विवश कर सकता होगा ठीक है इस तरह इंटरफ़ेस।

public delegate void FooDelegate<T>(T value) where T : IFooValue; 

public class FooContainer 
{ 
    public event FooDelegate<IFooValue> FooEvent; 

    protected void OnFooEvent(IFooValue value) 
    { 
     if (this.FooEvent != null) 
      this.FooEvent(value); 
    } 
} 

public interface IFooValue 
{ 
    string Name { get; set; }// just an example member 
} 

इस मामले में, आप जब तक वे इंटरफ़ेस IFooValue लागू के रूप में प्रकार के साथ घटना को बढ़ा सकते हैं।

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