यदि परीक्षण C # में सामान्य प्रकार का है


134

यदि कोई वस्तु सामान्य प्रकार की है तो मैं एक परीक्षण करना चाहूंगा। मैंने सफलता के बिना निम्नलिखित की कोशिश की है:

public bool Test()
{
    List<int> list = new List<int>();
    return list.GetType() == typeof(List<>);
}

मैं क्या गलत कर रहा हूं और मैं यह परीक्षा कैसे करूं?

जवाबों:


201

यदि आप यह देखना चाहते हैं कि क्या यह सामान्य प्रकार का उदाहरण है:

return list.GetType().IsGenericType;

यदि आप यह देखना चाहते हैं कि क्या यह सामान्य है List<T>:

return list.GetType().GetGenericTypeDefinition() == typeof(List<>);

जैसा कि जॉन बताते हैं, यह सटीक प्रकार की समानता की जांच करता है। रिटर्निंग का falseमतलब list is List<T>रिटर्न नहीं है false(यानी ऑब्जेक्ट को किसी List<T>वैरिएबल को नहीं सौंपा जा सकता है )।


9
हालांकि उपप्रकारों का पता नहीं लगेगा। मेरा जवाब देखिए। यह इंटरफेस के लिए भी बहुत कठिन है :(
जॉन स्कीट

1
अगर यह एक सामान्य प्रकार नहीं है तो GetGenericTypeDefinition पर कॉल फेंक देगा। सुनिश्चित करें कि आप पहले जाँच कर लें।
किलाहोफर

85

मेरा मानना ​​है कि आप केवल यह जानना नहीं चाहते हैं कि क्या प्रकार सामान्य है, लेकिन यदि कोई वस्तु किसी विशेष जेनेरिक प्रकार का उदाहरण है, तो प्रकार के तर्क को जाने बिना।

यह बहुत सरल नहीं है, दुर्भाग्य से। यह बहुत बुरा नहीं है यदि सामान्य प्रकार एक वर्ग है (जैसा कि इस मामले में है) लेकिन यह इंटरफेस के लिए कठिन है। यहाँ एक वर्ग के लिए कोड है:

using System;
using System.Collections.Generic;
using System.Reflection;

class Test
{
    static bool IsInstanceOfGenericType(Type genericType, object instance)
    {
        Type type = instance.GetType();
        while (type != null)
        {
            if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == genericType)
            {
                return true;
            }
            type = type.BaseType;
        }
        return false;
    }

    static void Main(string[] args)
    {
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new List<string>()));
        // False
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new string[0]));
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new SubList()));
        // True
        Console.WriteLine(IsInstanceOfGenericType(typeof(List<>),
                                                  new SubList<int>()));
    }

    class SubList : List<string>
    {
    }

    class SubList<T> : List<T>
    {
    }
}

संपादित करें: जैसा कि टिप्पणियों में कहा गया है, यह इंटरफेस के लिए काम कर सकता है:

foreach (var i in type.GetInterfaces())
{
    if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
    {
        return true;
    }
}

मुझे इस बात पर संदेह है कि इसके आसपास कुछ अजीबोगरीब मामले हो सकते हैं, लेकिन मुझे अभी इसके लिए कोई असफलता नहीं मिली है।


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

1
@ ग्रॉक्स: सच। मुझे अभी-अभी स्पॉट किया गया है कि मैं इसका जवाब देता हूं, हालांकि: "यह बहुत बुरा नहीं है यदि सामान्य प्रकार एक वर्ग है (जैसा कि इस मामले में है) लेकिन यह इंटरफेस के लिए कठिन है। यहां एक वर्ग के लिए कोड है"
जॉन स्कीट

1
अगर आपके पास <T> जानने का कोई तरीका नहीं है तो क्या होगा? जैसे, यह इंट, या स्ट्रिंग हो सकता है, लेकिन आप यह नहीं जानते हैं। यह उत्पन्न करता है, यह प्रतीत होता है, झूठी नकारात्मक ... इसलिए आपके पास उपयोग करने के लिए एक टी नहीं है, आप बस किसी वस्तु के गुणों को देख रहे हैं और एक सूची है। आपको कैसे पता चलेगा कि यह एक सूची है ताकि आप इसे अनपिल कर सकें? इससे मेरा मतलब है कि आपके पास कहीं भी एक टी नहीं है और न ही एक प्रकार का उपयोग करने के लिए। आप हर प्रकार का अनुमान लगा सकते हैं (क्या यह सूची <int> है? क्या यह सूची <string>?) है, लेकिन आप जो जानना चाहते हैं, वह यह है? उस प्रश्न का उत्तर देना कठिन लगता है।

@RiverC: हाँ, तुम सही हो - यह है , जवाब देने के लिए काफी कठिन विभिन्न कारणों के लिए। यदि आप केवल एक वर्ग के बारे में बात कर रहे हैं, तो यह बहुत बुरा नहीं है ... आप वंशानुक्रम के पेड़ पर चलते रह सकते हैं और देख सकते हैं कि आप List<T>किसी अन्य रूप में मारा या नहीं। यदि आप इंटरफेस शामिल करते हैं, तो यह वास्तव में मुश्किल है।
जॉन स्कीट

3
क्या आप समानता ऑपरेटर ( ) के बजाय IsInstanceOfGenericTypeकॉल के साथ लूप को बदल नहीं सकते हैं ? IsAssignableFrom==
slawekwin

7

आप डायनेमिक एल्थॉग का उपयोग करके छोटे कोड का उपयोग कर सकते हैं यह शुद्ध प्रतिबिंब की तुलना में धीमा हो सकता है:

public static class Extension
{
    public static bool IsGenericList(this object o)
    {
       return IsGeneric((dynamic)o);
    }

    public static bool IsGeneric<T>(List<T> o)
    {
       return true;
    }

    public static bool IsGeneric( object o)
    {
        return false;
    }
}



var l = new List<int>();
l.IsGenericList().Should().BeTrue();

var o = new object();
o.IsGenericList().Should().BeFalse();

7

ये मेरे दो पसंदीदा एक्सटेंशन तरीके हैं जो जेनेरिक प्रकार की जाँच के सबसे किनारे मामलों को कवर करते हैं:

के साथ काम करता है:

  • एकाधिक (सामान्य) इंटरफेस
  • एकाधिक (सामान्य) आधार वर्ग
  • एक अधिभार है जो विशिष्ट जेनेरिक प्रकार को 'आउट' कर देगा यदि यह सच हो जाता है (नमूने के लिए इकाई परीक्षण देखें)

    public static bool IsOfGenericType(this Type typeToCheck, Type genericType)
    {
        Type concreteType;
        return typeToCheck.IsOfGenericType(genericType, out concreteType); 
    }
    
    public static bool IsOfGenericType(this Type typeToCheck, Type genericType, out Type concreteGenericType)
    {
        while (true)
        {
            concreteGenericType = null;
    
            if (genericType == null)
                throw new ArgumentNullException(nameof(genericType));
    
            if (!genericType.IsGenericTypeDefinition)
                throw new ArgumentException("The definition needs to be a GenericTypeDefinition", nameof(genericType));
    
            if (typeToCheck == null || typeToCheck == typeof(object))
                return false;
    
            if (typeToCheck == genericType)
            {
                concreteGenericType = typeToCheck;
                return true;
            }
    
            if ((typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck) == genericType)
            {
                concreteGenericType = typeToCheck;
                return true;
            }
    
            if (genericType.IsInterface)
                foreach (var i in typeToCheck.GetInterfaces())
                    if (i.IsOfGenericType(genericType, out concreteGenericType))
                        return true;
    
            typeToCheck = typeToCheck.BaseType;
        }
    }

यहाँ एक परीक्षण बुनियादी (बुनियादी) कार्यक्षमता प्रदर्शित करने के लिए है:

 [Test]
    public void SimpleGenericInterfaces()
    {
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>)));
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>)));

        Type concreteType;
        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>), out concreteType));
        Assert.AreEqual(typeof(IEnumerable<string>), concreteType);

        Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>), out concreteType));
        Assert.AreEqual(typeof(IQueryable<string>), concreteType);


    }

0
return list.GetType().IsGenericType;

3
यह एक अलग प्रश्न के लिए सही है। इस प्रश्न के लिए, यह गलत है, क्योंकि यह समस्या का केवल आधा हिस्सा (पते से काफी कम) है।
ग्रॉक्सक्स

1
वास्तव में स्टेन आर का उत्तर प्रश्न का उत्तर देता है, लेकिन ओपी का वास्तव में मतलब था "परीक्षण यदि वस्तु C # में एक विशेष प्रकार का है", जिसके लिए यह उत्तर वास्तव में अपूर्ण है।
योयो

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

2
अब आप जानते हैं कि और आप अपने उत्तर को अधिक विशिष्ट और सही होने के लिए बेहतर बना सकते हैं।
पीटर इवान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.