.NET: अपनी स्थैतिक विधि में "यह" वर्ग के प्रकार को निर्धारित करें


94

एक गैर-स्थैतिक विधि में मैं उपयोग कर सकता था this.GetType()और यह वापस आ जाएगी Type। मैं Typeएक स्थिर विधि में समान कैसे प्राप्त कर सकता हूं ? बेशक, मैं सिर्फ typeof(ThisTypeName)इसलिए नहीं लिख सकता क्योंकि ThisTypeNameकेवल रनटाइम में जाना जाता है। धन्यवाद!


16
आप एक STATIC संदर्भ में हैं और टाइपऑफ़ (ThisTypeName) नहीं लिख सकते हैं? कैसे?
ब्रूनो रीस

1
स्थैतिक विधि के अंदर 'रनटाइम' जैसा कुछ भी नहीं है (यह मानते हुए कि आप एक तर्क के बारे में बात नहीं कर रहे हैं जो एक स्थैतिक विधि से पारित हो जाता है)। उस स्थिति में आप बस टाइपोफ (RelevantType) कह सकते हैं।
मनीष बसंती

2
एक स्थिर विधि आभासी नहीं हो सकती। आप पहले से ही प्रकार जानते हैं।
हंस पसंत १ant

7
एक सार से कई व्युत्पन्न वर्ग होंगे। आधार सार वर्ग में स्थिर शब्दकोश <Int, Type> है। इसलिए व्युत्पन्न कक्षाएं "स्थिर कंस्ट्रक्टरों में खुद को पंजीकृत करें" (dic.Add (N, T))। और हां, मुझे पता है कि प्रकार :) मैं थोड़ा आलसी हूं और पाठ को बदलना पसंद नहीं करता और सोच रहा था कि क्या "टी" रनटाइम में निर्धारित किया जा सकता है। कृपया मेरे झूठ का बहाना करें, क्योंकि प्रश्न को सरल बनाने के लिए यह आवश्यक था। और यह काम किया;) अब एक स्वीकृत समाधान है। धन्यवाद।
येगोर

एक उपवर्ग अपने सुपरक्लास के स्थिर तरीकों को विरासत में देता है, नहीं? क्या यह सुपरक्लास स्टैटिक विधि के लिए सब-क्लास के लिए उपयोगी होने के लिए कोई मतलब नहीं होगा? स्टेटिक का अर्थ बिना उदाहरण के होता है, निश्चित रूप से कॉमन बेस क्लास में कॉमन कोड का सिद्धांत स्टैटिक विधियों के साथ-साथ इंस्टैंस विधियों पर भी लागू होता है?
मैट कॉनॉली

जवाबों:


134

यदि आप 1 लाइनर की तलाश कर रहे हैं जो this.GetType()स्थिर तरीकों के लिए समान है , तो निम्न प्रयास करें।

Type t = MethodBase.GetCurrentMethod().DeclaringType

हालांकि यह सिर्फ उपयोग करने की तुलना में बहुत अधिक महंगा है typeof(TheTypeName)


1
यह ठीक काम करता है। धन्यवाद :) यह इतना महंगा नहीं है क्योंकि इसे काफी दुर्लभ कहा जाएगा।
येगोर

2
Entrase, "महंगी" से जारेड का मतलब है कि वे प्रोसेसर के लिए महंगा हैं, आमतौर पर धीमी गति से मतलब है। लेकिन उन्होंने कहा, "बहुत अधिक महंगा" धीमी अर्थ। शायद बिल्कुल भी धीमा नहीं है, जब तक कि आप एक रॉकेट-मार्गदर्शन प्रणाली को डिज़ाइन नहीं कर रहे हैं।
डैन रोसेनस्टार्क

1
मैंने देखा है GetCurrentMethod कुछ गंभीर प्रदर्शन समस्याओं का कारण बनता है। लेकिन जब से आप बस टाइप कर रहे हैं आप इसे कैश कर सकते हैं।
जोनाथन एलन

51
यह हमेशा उस वर्ग को लौटाता है जो वर्तमान पद्धति को लागू करता है, न कि वह वर्ग जिसे उपवर्गों के मामले में बुलाया गया था।
मैट कॉनॉली

3
मुझे लगता है कि यह त्रुटियों से बचने के लिए आसान है अगर कोड कभी भी अलग-अलग वर्ग के नामों या कुछ के लिए माइग्रेट हो जाता है, लेकिन एक अच्छा रीफैक्टरिंग टूल को typeof(TheTypeName)वैसे भी ध्यान रखना चाहिए ।
Nyerguds

59

ऐसा कुछ है जो अन्य उत्तरों में स्पष्ट नहीं किया गया है, और जो आपके विचार के लिए प्रासंगिक है केवल निष्पादन समय पर उपलब्ध है।

यदि आप स्थैतिक सदस्य को निष्पादित करने के लिए एक व्युत्पन्न प्रकार का उपयोग करते हैं, तो बाइनरी में वास्तविक प्रकार का नाम छोड़ दिया जाता है। उदाहरण के लिए, इस कोड को संकलित करें:

UnicodeEncoding.GetEncoding(0);

अब उस पर ildasm का उपयोग करें ... आप देखेंगे कि कॉल इस तरह से उत्सर्जित होती है:

IL_0002:  call       class [mscorlib]System.Text.Encoding 
[mscorlib]System.Text.Encoding::GetEncoding(int32)

कंपाइलर ने कॉल को हल कर दिया है Encoding.GetEncoding- कोई निशान नहीं UnicodeEncodingबचा है। यह "वर्तमान प्रकार" के आपके विचार को निरर्थक बनाता है, मुझे डर है।


24

एक अन्य समाधान एक आत्म-शोधक प्रकार का उपयोग करना है

//My base class
//I add a type to my base class use that in the static method to check the type of the caller.
public class Parent<TSelfReferenceType>
{
    public static Type GetType()
    {
        return typeof(TSelfReferenceType);
    }
}

फिर इसे विरासत में देने वाले वर्ग में, मैं एक आत्म संदर्भित प्रकार बनाता हूं:

public class Child: Parent<Child>
{
}

अब पेरेंट के अंदर कॉल टाइप टाइपऑफ (TSelfReferenceType) मिल जाएगा और बिना इंस्टेंट के कॉल करने वाले का टाइप वापस कर देगा।

Child.GetType();

-Rob


मैंने इसका उपयोग सिंगलटन पैटर्न के लिए किया है, अर्थात सिंगलटन <T> ... स्थैतिक सदस्य फिर त्रुटि संदेशों में टाइपो (टी) का उल्लेख कर सकते हैं या जहाँ भी इसकी आवश्यकता हो।
योयो

1
नमस्ते। मैं वास्तव में इस जवाब को पसंद करता हूं और इसकी सराहना करता हूं क्योंकि यह मुझे एक स्थिर आधार फ़ंक्शन से बच्चे के प्रकार को खोजने के लिए एक काम देता है।
बिल सॉफ्टवेयर इंजीनियर

1
अच्छा है। बहुत दुख की बात है कि C # में यह थोड़ा कोड डुप्लीकेशन के बिना नहीं किया जा सकता है।
प्रदर्शन नाम

इस वर्कअराउंड का एक और उदाहरण है stackoverflow.com/a/22532416/448568
स्टीवन डी सालास

6

आप thisस्थैतिक विधि का उपयोग नहीं कर सकते , इसलिए यह सीधे संभव नहीं है। हालांकि, अगर आपको किसी वस्तु के प्रकार की आवश्यकता है, तो बस GetTypeउस पर कॉल करें और thisउदाहरण को एक पैरामीटर बनाएं जिसे आपको पास करना होगा, जैसे:

public class Car {
  public static void Drive(Car c) {
    Console.WriteLine("Driving a {0}", c.GetType());
  }
}

यह एक गरीब डिजाइन की तरह लगता है, हालांकि। क्या आप वाकई अपने स्वयं के स्थैतिक विधि के अंदर ही उदाहरण के प्रकार को प्राप्त करना चाहते हैं? जो थोड़ा विचित्र लगता है। सिर्फ एक इंस्टेंस मेथड का इस्तेमाल क्यों नहीं किया जाता?

public class Car {
  public void Drive() { // Remove parameter; doesn't need to be static.
    Console.WriteLine("Driving a {0}", this.GetType());
  }
}

3

मुझे समझ में नहीं आता है कि आप टाइपोफ़ (ThisTypeName) का उपयोग क्यों नहीं कर सकते हैं। यदि यह एक गैर-सामान्य प्रकार है, तो यह काम करना चाहिए:

class Foo {
   static void Method1 () {
      Type t = typeof (Foo); // Can just hard code this
   }
}

यदि यह एक सामान्य प्रकार है, तो:

class Foo<T> {
    static void Method1 () {
       Type t = typeof (Foo<T>);
    }
}

क्या में यहां कुछ भूल रहा हूँ?


7
यह काम नहीं करेगा यदि आप फू से व्युत्पन्न एक क्लास बार बनाते हैं और फिर क्लास मेथड 1 वारिस करता है - तो Bar.Method1 पर कॉल अभी भी टाइपोफ (फू) प्रोसेस करेगा जो कि गलत है। विरासत में मिली विधि 1 को किसी तरह पता होना चाहिए कि यह बार में विकृत है, और फिर टाइपोफ (बार) प्राप्त करें।
जस्टमार्टिन

0

जब आपका सदस्य स्थिर होता है, तो आपको हमेशा पता रहेगा कि यह किस प्रकार का रनटाइम का हिस्सा है। इस मामले में:

class A
{
  public static int GetInt(){}

}
class B : A {}

आप कॉल नहीं कर सकते (संपादित करें: जाहिरा तौर पर, आप कर सकते हैं, नीचे टिप्पणी देखें, लेकिन आप अभी भी ए में कॉल करेंगे):

B.GetInt();

क्योंकि सदस्य स्थिर है, यह उत्तराधिकार परिदृश्यों में भाग नहीं लेता है। एर्गो, आप हमेशा जानते हैं कि प्रकार ए है।


4
आप B.GetInt () को कॉल कर सकते हैं - कम से कम, यदि आप निजी नहीं थे तो आप कर सकते हैं - लेकिन संकलन इसे A.GetInt () में कॉल कर देगा। कोशिश करो!
जॉन स्कीट

जॉन की टिप्पणी पर ध्यान दें: C # में डिफ़ॉल्ट दृश्यता निजी है, इसलिए आपका उदाहरण काम नहीं करता है।
डेन रोसेनस्टार्क

0

मेरे उद्देश्यों के लिए, मुझे @ टी-मोटी का विचार पसंद है। भले ही मैंने वर्षों तक "सेल्फ-रेफ़रिंग टाइप" जानकारी का उपयोग किया हो, लेकिन बेस क्लास को संदर्भित करना बाद में करना कठिन है।

उदाहरण के लिए (ऊपर से @Rob Leclerc उदाहरण का उपयोग करके):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

इस पैटर्न के साथ काम करना चुनौतीपूर्ण हो सकता है, उदाहरण के लिए; आप फ़ंक्शन कॉल से बेस क्लास कैसे लौटाते हैं?

public Parent<???> GetParent() {}

या कास्टिंग कब टाइप करें?

var c = (Parent<???>) GetSomeParent();

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

class BaseClass
{
    // All non-derived class methods goes here...

    // For example:
    public int Id { get; private set; }
    public string Name { get; private set; }
    public void Run() {}
}

class BaseClass<TSelfReferenceType> : BaseClass
{
    // All derived class methods goes here...

    // For example:
    public TSelfReferenceType Foo() {}
    public void Bar(TSelfRefenceType obj) {}
}

अब आप (अधिक) आसानी से काम कर सकते हैं BaseClass। हालाँकि, कई बार, मेरी वर्तमान स्थिति की तरह, जहाँ बेस क्लास के भीतर से व्युत्पन्न वर्ग को उजागर करना आवश्यक नहीं है, और @ M-moty के सुझाव का उपयोग करना सही दृष्टिकोण हो सकता है।

हालाँकि, @ M-moty कोड का उपयोग केवल तब तक काम करता है जब तक कि बेस क्लास में कॉल स्टैक में कोई इंस्टेंस कंस्ट्रक्टर न हो। दुर्भाग्य से मेरे बेस क्लासेज इंस्टेंस कंस्ट्रक्टर्स का उपयोग करते हैं।

इसलिए, यहाँ मेरा एक्सटेंशन तरीका है जो बेस बेस क्लास 'इंस्टेंस' कंस्ट्रक्टर्स को ध्यान में रखता है:

public static class TypeExtensions
{
    public static Type GetDrivedType(this Type type, int maxSearchDepth = 10)
    {
        if (maxSearchDepth < 0)
            throw new ArgumentOutOfRangeException(nameof(maxSearchDepth), "Must be greater than 0.");

        const int skipFrames = 2;  // Skip the call to self, skip the call to the static Ctor.
        var stack = new StackTrace();
        var maxCount = Math.Min(maxSearchDepth + skipFrames + 1, stack.FrameCount);
        var frame = skipFrames;

        // Skip all the base class 'instance' ctor calls. 
        //
        while (frame < maxCount)
        {
            var method = stack.GetFrame(frame).GetMethod();
            var declaringType = method.DeclaringType;

            if (type.IsAssignableFrom(declaringType))
                return declaringType;

            frame++;
        }

        return null;
    }
}

0

संपादित करें यह विधि केवल तभी काम करेगी जब आप निष्पादन योग्य / पुस्तकालय के साथ पीडीबी फाइलों को तैनात करते हैं, जैसा कि मार्मनल ने मुझे बताया है।

अन्यथा पता लगाने के लिए एक बड़ा मुद्दा होगा: विकास में अच्छी तरह से काम करता है, लेकिन शायद उत्पादन में नहीं।


यूटिलिटी मेथड, अपने कोड के हर स्थान से, जरूरत पड़ने पर कॉल करें।

public static Type GetType()
{
    var stack = new System.Diagnostics.StackTrace();

    if (stack.FrameCount < 2)
        return null;

    return (stack.GetFrame(1).GetMethod() as System.Reflection.MethodInfo).DeclaringType;
}

1
StackTrace केवल डिबग बिल्ड
markmnl

सही नहीं है: जब आप तैनाती मोड में .pdb फ़ाइलों को भी जारी करते हैं तो StackTrace avaible होगा। stackoverflow.com/questions/2345957/…
T-moty

मै तुम्हारा मतलब समझ गया। स्वीकार्य नहीं है कि एक विधि केवल तभी काम करती है जब पीडीबी फाइलें तैनात की जाती हैं। मैं उत्तर को संपादित करूंगा
T-moty
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.