2009-03-13 12 views
13

क्या कोई जेनेरिक में इस व्यवहार को समझा सकता है?सी # जेनरिक फ़ंक्शन

मैं एक पक्ष टिप्पणी पर सी #

protected virtual void LoadFieldDataEditor <T> (ref T control, string strFieldName) where T : Control 
{ 
    //T can be different types of controls inheriting from System.Web.UI.Control 
    if (control is TextBox) 
    { 
    //This line gives an error 
    //((TextBox)control).Text = "test"; 

    //This line works! 
    (control as TextBox).Text = "Test"; 
    } 
} 

में एक सामान्य समारोह है, मैं स्विच मामला है जब मैं एक "नियंत्रण पाठ बॉक्स है" जाँच के प्रकार के कर रहा हूँ का उपयोग कर सकते हैं?

संपादित करें:

त्रुटि संदेश जोड़ने के लिए क्षमा करें क्षमा करें!

ये रहा:

Error 3 Cannot convert type 'T' to 'TextBox' 

संपादित करें:

हम जेनरिक के बारे में बात कर रहे हैं, मैं एक और सवाल है। ,

विधि एक और सामान्य प्रकार

protected virtual void LoadFieldDataEditor <T1, T2> (T1 control, T2 objData, string strFieldName) where T1 : Control where T2 : BaseDataType 
{ 
    //I will need to access field1. 
    //I don't know at compile time if this would be SomeType1 or 
//SomeType2 but all of them inherit from BaseDataType. 

    //Is this possible using generics? 
} 

public abstract class BaseDataType {} 

public class SomeType1 : BaseDataType 
{ 
    string field1; 
    string field2; 
} 
+0

जब आप किसी त्रुटि का अर्थ पूछ रहे हैं, तो यह वास्तव में मददगार है कि त्रुटि क्या है। बस पुन: पेश करने की कोशिश कर रहा है ... –

+0

त्रुटि क्या है? –

+0

@ जोन स्कीट: अरे ... मुझे नहीं पता था कि आप इस मामले में थे ... –

उत्तर

21

क्या एक सामान्य प्रकार के लिए परिवर्तित किया जा सकता के लिए नियमों को शामिल करने के लिए विस्तार किया गया है काफी मुश्किल कर रहे हैं (अगर मैं एक नई पोस्ट शुरू करने के लिए किया था यकीन नहीं था) और कभी-कभी इस मामले में, counterintuitive। विवरण के लिए सी # spec के सेक्शन 6.2.6 देखें। ऐसे स्थान हैं जहां वे लापरवाह हो सकते हैं, और मुझे लगता है कि यह उनमें से एक है। आप object पर जा सकते हैं और फिर फिर से नीचे जा सकते हैं, लेकिन यह बदसूरत है।

इस मामले में बेहतर समाधान हो जाएगा:

protected virtual void LoadFieldDataEditor <T> (ref T control, 
               string strFieldName) 
    where T : Control 
{ 
    TextBox textBox = control as TextBox; 
    if (textBox != null) 
    { 
     textBox.Text = "test"; 
    } 
} 
अलावा कुछ और से

, यह केवल दो के बजाय एक ही निष्पादन समय की जांच की आवश्यकता है।

साइड नोट के लिए: नहीं, आप स्विच/केस प्रकारों का उपयोग नहीं कर सकते हैं। (आप उस प्रकार का नाम प्राप्त कर सकते हैं और उस पर स्विच कर सकते हैं, लेकिन यह भयानक होगा।)

+0

पढ़ें इस विधि में आप एक नया टेक्स्टबॉक्स बना रहे हैं। इस बदलाव पर पाठ को उस पर पाठ को बदल देगा जिसे एक परम (रेफ कंट्रोल) के रूप में भेजा गया था? – DotnetDude

+0

नहीं, यह विधि एक नया टेक्स्टबॉक्स नहीं बनाती है। आपको लगता है कि कौन सी रेखा एक नया बनाता है? मुझे दृढ़ता से संदेह है कि आपको वास्तव में रेफरी द्वारा नियंत्रित होने की आवश्यकता नहीं है ... –

+0

मैंने यह लाइन सोचा - टेक्स्टबॉक्स टेक्स्टबॉक्स = टेक्स्टबॉक्स के रूप में नियंत्रण; ने एक नया टेक्स्टबॉक्स बनाया। मुझे अपने "पास द्वारा वैल" पर ब्रश करना पड़ सकता है और रेफरी अवधारणाओं से गुज़रना पड़ सकता है। मेरी समझ तब थी जब आप मूल्य से गुजरते थे (यानि, बिना रेफरी) यह एक नई मेमोरी लोकेशन में एक नया var बनाता है और स्रोत मान – DotnetDude

1

पहली पंक्ति कंपाइलर त्रुटि देता है: "टाइप टी को टेक्स्टबॉक्स में परिवर्तित नहीं किया जा सकता है।" उस तरह का कास्ट केवल कानूनी है यदि संकलक यह जान सकता है कि प्रारंभिक वर्ग को अंतिम श्रेणी में परिवर्तित करना संभव है। चूंकि टी कुछ भी हो सकता है, इसलिए कंपाइलर को जानने का कोई तरीका नहीं है। भले ही आप रनटाइम पर जांच कर रहे हों, यह संकलक को प्रसन्न नहीं करता है। दूसरी तरह का कास्ट ठीक है, क्योंकि अगर कलाकार काम नहीं करता है तो यह सिर्फ शून्य हो जाएगा। संपादित करें: जैसा कि tuinstoel बताता है, कास्टिंग के नियम मेरे वर्णित की तुलना में अधिक जटिल हैं।

+0

मेरी प्रतिक्रिया देखें। स्पष्टीकरण के लिए – tuinstoel

0

@rossfabricant के जवाब में।

यह इतना आसान नहीं है, पहली विधि संकलित करता है, दूसरा नहीं।

void Test(Control control) 
{ 
    if (control is TextBox) 
    { 
     ((TextBox)control).Text = "test"; 
    } 
} 

void Test<T>(T control) where T : Control 
{ 
    if (control is TextBox) 
    { 
     ((TextBox)control).Text = "test"; 
    } 
} 
3

मैं अत्यधिक इस होने की पुनर्रचना करने की सलाह देते हैं:

protected virtual void LoadFieldDataEditor(Control control, string strFieldName) 

में कुछ टिप्पणी में उल्लेख किया है, इस विधि बिल्कुल जेनरिक जरूरत नहीं है।

चूंकि आप नियंत्रण में बाधा डाल रहे हैं, इसलिए आप बेस क्लास को जानते हैं, और यह एक संदर्भ प्रकार (नियंत्रण) है, ताकि आप जेनेरिक और रेफरी पैरामीटर घोषणा से बच सकें।

चूंकि नियंत्रण एक संदर्भ प्रकार है, इसलिए आप विधि में इसकी गुणों को बदलने के लिए स्वतंत्र हैं, और यह सही तरीके से काम करेगा। सेटिंग। टेक्स्ट, इत्यादि, वही करेगा जो आप करने की कोशिश कर रहे हैं, लेकिन बहुत आसान हो।

इसकी बहुत कम संभावना है कि आप इसे होने की जरूरत सकता है:

protected virtual void LoadFieldDataEditor(ref Control control, string strFieldName) 

लेकिन यह केवल यदि आप अपने विधि के अंदर नियंत्रण पुन: असाइन करने जा रहे थे की आवश्यकता होगी (यानी: control = new TextBox();)। मैं दृढ़ता से ऐसा करने की सिफारिश करता हूं, क्योंकि इससे कुछ अप्रत्याशित व्यवहार हो सकता है और यह स्पष्ट नहीं होगा। यदि आप एक नया पैरामीटर बनाने का प्रयास कर रहे हैं, आउट पैरामीटर का उपयोग कर रहे हैं, या सिर्फ नए नियंत्रण को वापस करने से सबकुछ अधिक स्पष्ट हो जाएगा।

इसके अलावा, सामान्य रूप से, सामान्य तरीकों से बचने के लिए एक अच्छा विचार है जब तक कि उन्हें शामिल करने का कोई अच्छा कारण न हो। FxCop टीम ने अपने उपयोग को हतोत्साहित करने की कोशिश कर रहे कुछ नियम जोड़े (और बाद में हटा दिए गए) क्योंकि वे लंबे समय तक कोड को कम समझने योग्य होते हैं। जेनेरिक तरीकों का उपयोग करने के कई अच्छे कारण हैं, लेकिन इसके उपयोग की आवश्यकता नहीं है, इसलिए मैं उन्हें टालने की सलाह दूंगा।

+0

धन्यवाद। पाठ को असाइन करना केवल प्रश्न पूछने के उद्देश्य से था। हकीकत में, मेरे पास बहुत सी चीजें चल रही हैं। लेकिन हाँ, मैंने रेफरी का उपयोग न करने के लिए रिफैक्टर किया और यह बहुत अच्छा काम करता है! धन्यवाद – DotnetDude

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