2010-02-18 18 views
8

मैं विरासत वर्ग के Type को कैसे प्राप्त करूं और इसे कक्षा के मूल निर्माता में भी उत्तीर्ण कर दूं? नीचे दिए गए कोड नमूना देखें:बेस ऑब्जेक्ट प्रकार को बेस कन्स्ट्रक्टर कॉल में पास करें

// VeryBaseClass is in an external assembly 
public abstract class VeryBaseClass 
{ 
    public VeryBaseClass(string className, MyObject myObject) 
    { 

    } 
} 

// BaseClass and InheritedClass are in my assembly 
public abstract class BaseClass : VeryBaseClass 
{ 
    public BaseClass(MyObject myObject) : 
     base(this.GetType().Name, myObject) // can't reference "this" (Type expected) 
    { 

    } 
} 

public class InheritedClass : BaseClass 
{ 
    public InheritedClass(MyObject myObject) 
    { 

    } 
} 

लाइन क्योंकि मैं this अभी तक संदर्भ नहीं दे सकता, के रूप में वस्तु का निर्माण पूरा नहीं किया है और इसलिए मौजूद नहीं है base(typeof(this).Name, myObject) काम नहीं करता।

क्या वर्तमान में निर्माण करने वाले ऑब्जेक्ट के Type को पकड़ना संभव है?

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

orsogufo suggested के रूप में नमूना सही किया, लेकिन अभी भी काम नहीं करता है, के रूप में this अनिर्धारित रहता है।

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

बस स्पष्ट करने के लिए, मैं "InheritedClass" के साथ समाप्त करना चाहते हैं VeryBaseClass(string className, MyObject myObject) निर्माता में पारित कर दिया जा रहा है।

+1

आप ऐसा क्यों करना चाहते हैं?एक कन्स्ट्रक्टर को परवाह नहीं करना चाहिए कि इसे अपनी कक्षा या व्युत्पन्न कक्षा को तुरंत चालू करने के लिए बुलाया जा रहा है या नहीं। – AakashM

+1

मुझे लगता है कि आप बिंदु खो रहे हैं। बाहरी असेंबली जो मेरे द्वारा उपयोग किए जाने वाले ढांचे के बेस क्लास को परिभाषित करती है, उसे कन्स्ट्रक्टर में पारित करने के लिए स्वयं की कक्षा के स्ट्रिंग प्रस्तुति की आवश्यकता होती है। अब तक मैं इसे अंदर डाल रहा हूं जैसा कि आप उम्मीद करेंगे (एक स्ट्रिंग के रूप में) लेकिन मैं इसे पसंद करूंगा अगर यह सैनिटी के लिए रनटाइम पर काम करेगा। – Codesleuth

+1

ओह, मैं देखता हूं, यह आपकी कक्षा नहीं है। मुझे अभी भी लगता है कि यह एक बुरी बात है कि यह परवाह करता है :) – AakashM

उत्तर

14

आह हा: मुझे पता है कि तुम क्या से बचना चाहता था लेकिन अगर मैं इन आवश्यकताओं के साथ एक 3 पार्टी विधानसभा कॉल करने के लिए की जरूरत है मैं सिर्फ अपनी ही प्रकार निर्दिष्ट करने के प्रत्येक वर्ग की आवश्यकता होगी है! मुझे एक समाधान मिला। आप इसे जेनेरिक के साथ कर सकते हैं:

public abstract class VeryBaseClass 
{ 
    public VeryBaseClass(string className, MyObject myObject) 
    { 
     this.ClassName = className; 
    } 

    public string ClassName{ get; set; } 
} 
public abstract class BaseClass<T> : VeryBaseClass 
{ 
    public BaseClass(MyObject myObject) 
     : base(typeof(T).Name, myObject) 
    { 
    } 
} 

public class InheritedClass : BaseClass<InheritedClass> 
{ 
    public InheritedClass(MyObject myObject) 
     : base(myObject) 
    { 

    } 
} 
+0

हे भगवान, प्रतिभा! जब मैं अपना टीएफएस स्रोत नियंत्रण लेआउट बुझाना समाप्त कर दूंगा तो मैं इसका परीक्षण करूंगा :) – Codesleuth

+0

बढ़िया, यह काम करता है!हालांकि इसका मतलब है कि मेरे मौजूदा वर्गों को बदलने के लिए मेरे पास बहुत काम है, लेकिन अंत में यह इसके लायक होगा। धन्यवाद :) – Codesleuth

+2

अचानक, सीआरटीपी (उर्फ उत्सुकता से आवर्ती टेम्पलेट पैटर्न) प्रकट होता है! :) (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern देखें) – Macke

3

GetType()। नाम काम नहीं करता है?

+1

नहीं, क्योंकि यह स्पष्ट रूप से "इस" का उपयोग करता है जिसे आप कन्स्ट्रक्टर चेनिंग तर्कों का मूल्यांकन करने के लिए उपयोग नहीं कर सकते हैं। –

+0

क्षमा करें, मेरा मतलब एक निर्माता श्रृंखला में नहीं था, मेरा मतलब था कि वेरिबेस क्लास का निर्माता गेटटाइप() का उपयोग कर सकता है। इसे पारित होने की अपेक्षा के बजाय नाम। – pdr

+0

@pdr: यह मानता है कि VeryBaseClass हमेशा वर्तमान प्रकार का नाम चाहता है; जबकि यह कुछ मामलों में एक उचित डिजाइन हो सकता है, यह हमेशा नहीं होता है। मैं इसे एक व्यापक प्रश्न के रूप में देख रहा हूं "जब आप एक कन्स्ट्रक्टर चेन तर्क में 'इस' का उपयोग करना चाहते हैं तो आप क्या करते हैं" - क्योंकि आप हमेशा कार्यक्षमता को विरासत पेड़ तक नहीं दबा सकते हैं। –

3

सम्भावित समाधान:

class VeryBase { 
    public VeryBase(string name) { 
     Console.WriteLine(name); 
    } 
} 

class Base<T> : VeryBase where T : Base<T> { 
    protected Base() 
     : base(typeof(T).Name) { 
    } 
} 

class Derived : Base<Derived> { 
    public Derived() { 
    } 
} 

class Program { 
    public static void Main(params string[] args) { 
     Derived d = new Derived(); 
    } 
} 
+0

क्षमा करता हूं, आप सही हैं। यह। गेट टाइप टाइप होना चाहिए था मेरा उदाहरण। हां, 'यह' अपरिभाषित है। – Codesleuth

+0

आह, ठीक है ... ठीक है, मैंने अपनी पोस्ट को संभव के साथ अपडेट किया है (भले ही उपयोग करने में बहुत आसान न हो) समाधान ... –

+0

यह ट्रिकी बन जाता है अगर आप विरासत की एक और परत जोड़ना चाहते हैं, और यह व्युत्पन्न वर्ग के बजाय बेस क्लास में Type.Name का उपयोग करने का तर्क डालता है। (प्रश्न में, यह तर्क तीन की मध्यम परत में है।) –

5

मैं अब Google Wave Robot .NET API जहाँ मैं विशेषताओं के आधार पर कुछ मूल्यों में निर्माता पास बनाना चाहते थे में से पहले ठीक उसी दर्द था। आप derived type और base type के कोड में मेरे समाधान पर एक नज़र डाल सकते हैं। असल में मैं बेस कन्स्ट्रक्टर के लिए एक प्रतिनिधि को पास करता हूं, और फिर उस प्रतिनिधि को प्रतिनिधि को "इस" में गुजरता हूं। तो आपके मामले में आप होगा:

public VeryBaseClass(Func<VeryBaseClass, string> classNameProvider) 
{ 
    this.name = classNameProvider(this); 
} 

और

public BaseClass() : base(FindClassName) 
{ 
} 

private static string FindClassName(VeryBaseClass @this) 
{ 
    return @this.GetType().Name; 
} 

यह वास्तव में बदसूरत है, लेकिन यह काम करता है।

संपादित करें: यह दृष्टिकोण केवल तभी काम करता है जब आप अपना बेस क्लास कन्स्ट्रक्टर दिखाएंगे; यदि आप नहीं कर सकते, मुझे यकीन है कि यह वास्तव में सभी :(

+0

मैंने कभी पहले @ @ यह' नहीं देखा है, और Google को भ्रमित करने लगता है। क्या यह सिर्फ एक विधि को कॉल करने की अनुमति देता है कोई पैरामीटर नहीं है, और स्वचालित रूप से वर्तमान ऑब्जेक्ट को अंदर रखता है? (इस तरह मैं इसे देखता हूं) – Codesleuth

+1

नहीं, इसके सामने @ यह सिर्फ कंपाइलर को पहचानकर्ता के रूप में 'इस' पर विचार करने के लिए कह रहा है (इसे कीवर्ड से अलग करने के लिए)। यह: http://msdn.microsoft.com/en-us/library/aa664670%28VS.71%29.aspx। आप किसी भी पैरामीटर नाम के साथ '@this' को प्रतिस्थापित कर सकते हैं। –

+0

'तर्क' 1 ': से कनवर्ट नहीं किया जा सकता 'स्ट्रिंग' '' स्ट्रिंग '' मुझे लगता है कि मुझे यहां उल्लेख करना चाहिए कि हालांकि मेरा उदाहरण बेस क्लास द्वारा उपयोग किए जाने वाले एक पैरामीटर को दिखाता है, मेरा वास्तविक कार्यान्वयन कुछ और उपयोग करता है। मैं इसे प्रतिबिंबित करने के लिए प्रश्न अपडेट करूंगा। – Codesleuth

0

फिर भी एक और विकल्प पर संभव है नहीं कर रहा हूँ ...

// VeryBaseClass is in an external assembly 
public abstract class VeryBaseClass 
{ 
    public VeryBaseClass(string className) 
    { 
     Console.WriteLine(className); 
    } 
} 

// BaseClass and InheritedClass are in my assembly 
public abstract class BaseClass : VeryBaseClass 
{ 
    public BaseClass(string className) 
     : 
     base(className) 
    { 

    } 
} 

public class InheritedClass : BaseClass 
{ 
    public InheritedClass() 
     : base(typeof(InheritedClass).Name) 
    { 
    } 
} 
+0

यह वर्ग स्ट्रिंग को स्ट्रिंग के रूप में टाइप करने जैसा ही होगा। मैं 'इनहेरिट क्लास' से 'बेस क्लास' कन्स्ट्रक्टर में कुछ भी नहीं करने के लिए बचाना चाहता था। – Codesleuth

3

तो रनटाइम पर विरासत में मिला वर्ग के प्रकार का निर्धारण करने की क्षमता से ज्यादा महत्वपूर्ण है प्रदर्शन आप StackTrace पर एक नज़र देखने के लिए जहां निर्माता से बुलाया जा रहा है कर सकते हैं आप अधिक मान्यताओं में कोड करने के लिए जब इस उदाहरण में GetInheritedClassName बुला आवश्यकता हो सकती है:।

public abstract class BaseClass : VeryBaseClass 
{ 
    private static string GetInheritedClassName 
    { 
     get 
     { 
      // Get the current Stack 
      StackTrace currentStack = new StackTrace(); 
      MethodBase method = currentStack.GetFrame(1).GetMethod(); 

      // 1st frame should be the constructor calling 
      if (method.Name != ".ctor") 
       return null; 

      method = currentStack.GetFrame(2).GetMethod(); 

      // 2nd frame should be the constructor of the inherited class 
      if (method.Name != ".ctor") 
       return null; 

      // return the type of the inherited class 
      return method.ReflectedType.Name; 
     } 
    } 

    public BaseClass(MyObject myObject) : 
     base(GetInheritedClassName, myObject) 
    { 

    } 
} 

मैं गतिशील करने के लिए एक शानदार तरीका नहीं सोच सकते हैं बिना विरासत वर्ग का नाम प्राप्त करें प्रदर्शन प्रभाव।

public abstract class BaseClass : VeryBaseClass 
{ 
    public BaseClass(string className, MyObject myObject) : 
     base(className, myObject) 
    { 

    } 
} 

public class InheritedClass : BaseClass 
{ 
    public InheritedClass(MyObject myObject) : base("InheritedClass", myObject) 
    { 

    } 
} 
+0

मुझे इस उत्तर की संसाधनता पसंद है, लेकिन आप इसके बारे में सही हैं कि यह प्रदर्शन गहन है। मेरे कोड की समीक्षा करने के बाद, मैं देख सकता हूं कि मैं इन कोडों में से कई को अपने कोड में किसी भी समय एक साथ नहीं बना सकता, इसलिए यह निश्चित रूप से व्यवहार्य है। निश्चित रूप से एक +1 उत्तर :) – Codesleuth

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