जांचें कि क्या कोई वर्ग सामान्य वर्ग से लिया गया है


309

मेरी परियोजना में व्युत्पन्न वर्ग के साथ एक सामान्य वर्ग है।

public class GenericClass<T> : GenericInterface<T>
{
}

public class Test : GenericClass<SomeType>
{
}

क्या यह पता लगाने का कोई तरीका है कि क्या कोई Typeवस्तु प्राप्त हुई है GenericClass?

t.IsSubclassOf(typeof(GenericClass<>))

काम नहीं करता।

जवाबों:


430

इस कोड को आज़माएं

static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
    while (toCheck != null && toCheck != typeof(object)) {
        var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
        if (generic == cur) {
            return true;
        }
        toCheck = toCheck.BaseType;
    }
    return false;
}

4
यह कोड का एक मीठा टुकड़ा है, मुझे कहना होगा। जबकि लूप कार्यान्वयन अनावश्यक पुनरावृत्ति प्रदर्शन हिट से भी बचता है। यह मेटा-जेनेरिक प्रश्न का एक सुंदर और सुंदर समाधान है।
एनोक्रॉनॉल - आनंदगोपाल परदेशू

2
मैंने इस पद्धति को अपने फ्रेमवर्क में अपने रिफ्लेक्शनियन्टिल्स स्टैटिक क्लास में जोड़ा है, और मैंने इसे टाइप टॉक = obj.GetType () के रूप में विधि के भीतर चेक को परिभाषित करके ऑब्जेक्ट के लिए एक विस्तार विधि के रूप में भी अनुकूलित किया है; "यह ऑब्जेक्ट ओब्ज" पहला पैरामीटर है।
एनोक्रॉनॉल - आनंदगोपाल परदेशू

11
जबकि लूप तब नहीं टूटेगा यदि चेकचेक प्रकार एक वर्ग (यानी, इंटरफ़ेस) नहीं है। यह एक NullReferenceException का कारण होगा।
जद कोर्टयेक

2
यह भी सच वापस आ जाएगा अगर चेक सामान्य प्रकार है जिसे आप खोज रहे हैं।
oillio

14
यह केवल ठोस प्रकार की विरासत के लिए काम करता है ... टेस्ट केस: बूल अपेक्षित = सच; बूल वास्तविक = कार्यक्रम। SsubclassOfRawGeneric (टाइपोफ़ (IEnumerable <>), टाइपोफ़ (सूची <string>); Assert.AreEqual (अपेक्षित, वास्तविक); // विफल
बॉबी

90

(एक बड़े पैमाने पर पुनर्लेखन के कारण लिखा गया)

JaredPar का कोड उत्तर शानदार है, लेकिन मेरे पास एक टिप है जो इसे अनावश्यक बना देगा यदि आपके जेनेरिक प्रकार मान प्रकार के मापदंडों पर आधारित नहीं हैं। मुझे इस बात पर लटकाया गया कि "is" ऑपरेटर काम क्यों नहीं करेगा, इसलिए मैंने भविष्य के संदर्भ के लिए अपने प्रयोग के परिणामों का भी दस्तावेजीकरण किया है। कृपया इसकी स्पष्टता बढ़ाने के लिए इस उत्तर को बढ़ाएँ।

सुझाव:

यदि आप यह सुनिश्चित करते हैं कि आपका जेनेरिकक्लास कार्यान्वयन एक सामान्य गैर-जेनेरिक आधार वर्ग जैसे कि जेनरिकक्लासबेस से विरासत में मिला है, तो आप बिना किसी परेशानी के एक ही सवाल पूछ सकते हैं:

typeof(Test).IsSubclassOf(typeof(GenericClassBase))

IsSubclassOf ()

मेरा परीक्षण इंगित करता है कि IsSubclassOf () पैरामीटर रहित जेनेरिक प्रकारों पर काम नहीं करता है

typeof(GenericClass<>)

जबकि यह साथ काम करेगा

typeof(GenericClass<SomeType>)

इसलिए निम्नलिखित कोड GenericClass <> के किसी भी व्युत्पत्ति के लिए काम करेगा, यह मानते हुए कि आप SomeType के आधार पर परीक्षण करने के इच्छुक हैं:

typeof(Test).IsSubclassOf(typeof(GenericClass<SomeType>))

केवल एक बार मैं कल्पना कर सकता हूं कि आप GenericClass द्वारा परीक्षण करना चाहेंगे <> प्लग-इन फ्रेमवर्क परिदृश्य में है।


विचार "ऑपरेटर" है

डिज़ाइन-टाइम C पर # पैरामीटर रहित जेनरिक के उपयोग की अनुमति नहीं देता है क्योंकि वे अनिवार्य रूप से उस बिंदु पर पूर्ण CLR प्रकार नहीं होते हैं। इसलिए, आपको मापदंडों के साथ सामान्य चर घोषित करना चाहिए, और इसीलिए "ऑपरेटर" ऑब्जेक्ट्स के साथ काम करने के लिए इतना शक्तिशाली है। संयोग से, "is" ऑपरेटर भी पैरामीटर रहित जेनेरिक प्रकारों का मूल्यांकन नहीं कर सकता है।

"है" ऑपरेटर इंटरफेस सहित पूरी विरासत श्रृंखला का परीक्षण करेगा।

तो, किसी भी वस्तु का एक उदाहरण दिया गया है, निम्नलिखित विधि चाल होगी:

bool IsTypeof<T>(object t)
{
    return (t is T);
}

यह निरर्थक है, लेकिन मुझे लगा कि मैं आगे जाऊंगा और हर किसी के लिए इसकी कल्पना करूंगा।

दिया हुआ

var t = new Test();

कोड की निम्नलिखित पंक्तियाँ सही होंगी:

bool test1 = IsTypeof<GenericInterface<SomeType>>(t);

bool test2 = IsTypeof<GenericClass<SomeType>>(t);

bool test3 = IsTypeof<Test>(t);

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

bool IsTypeofGenericClass<SomeType>(object t)
{
    return (t is GenericClass<SomeType>);
}

तो आप इस तरह का परीक्षण करेंगे:

bool test1 = IsTypeofGenericClass<SomeType>(t);

2
विश्लेषण और परीक्षण के लिए +1। साथ ही, आपका जवाब मेरे मामले में बहुत उपयोगी था।
गुइलेर्मो गुतिरेज

3
यह ध्यान दिया जाना चाहिए कि कंपाइलर .IsSubclassOf (typeof (GenericClass <>)) के साथ पूरी तरह से खुश है, यह सिर्फ वही नहीं करता है जो आप चाहते हैं।
user2880616

2
लेकिन क्या होगा यदि SomeType संकलन समय पर ज्ञात नहीं है?
रयान द लीच

संपूर्ण चर्चा का विषय तब था जब आपके पास केवल एक Typeवस्तु हो।
जोनाथन वुड

@JonathanWood यही कारण है कि ऊपर मेरा जवाब typeofऑपरेटर के साथ काम कर रहा है । डॉक्स के अनुसार: "टाइपऑफ़ ऑपरेटर का उपयोग एक प्रकार के लिए System.Type ऑब्जेक्ट को प्राप्त करने के लिए किया जाता है।"
एनोक्रॉनॉल - आनंदगोपाल परदेशू

33

मैंने इनमें से कुछ नमूनों के माध्यम से काम किया और पाया कि उनमें कुछ मामलों में कमी थी। यह संस्करण सभी प्रकार की जेनरिक के साथ काम करता है: प्रकार, इंटरफेस और इसके प्रकार की परिभाषा।

public static bool InheritsOrImplements(this Type child, Type parent)
{
    parent = ResolveGenericTypeDefinition(parent);

    var currentChild = child.IsGenericType
                           ? child.GetGenericTypeDefinition()
                           : child;

    while (currentChild != typeof (object))
    {
        if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
            return true;

        currentChild = currentChild.BaseType != null
                       && currentChild.BaseType.IsGenericType
                           ? currentChild.BaseType.GetGenericTypeDefinition()
                           : currentChild.BaseType;

        if (currentChild == null)
            return false;
    }
    return false;
}

private static bool HasAnyInterfaces(Type parent, Type child)
{
    return child.GetInterfaces()
        .Any(childInterface =>
        {
            var currentInterface = childInterface.IsGenericType
                ? childInterface.GetGenericTypeDefinition()
                : childInterface;

            return currentInterface == parent;
        });
}

private static Type ResolveGenericTypeDefinition(Type parent)
{
    var shouldUseGenericType = true;
    if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent)
        shouldUseGenericType = false;

    if (parent.IsGenericType && shouldUseGenericType)
        parent = parent.GetGenericTypeDefinition();
    return parent;
}

यहाँ इकाई परीक्षण भी हैं:

protected interface IFooInterface
{
}

protected interface IGenericFooInterface<T>
{
}

protected class FooBase
{
}

protected class FooImplementor
    : FooBase, IFooInterface
{
}

protected class GenericFooBase
    : FooImplementor, IGenericFooInterface<object>
{

}

protected class GenericFooImplementor<T>
    : FooImplementor, IGenericFooInterface<T>
{
}


[Test]
public void Should_inherit_or_implement_non_generic_interface()
{
    Assert.That(typeof(FooImplementor)
        .InheritsOrImplements(typeof(IFooInterface)), Is.True);
}

[Test]
public void Should_inherit_or_implement_generic_interface()
{
    Assert.That(typeof(GenericFooBase)
        .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}

[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass()
{
    Assert.That(typeof(GenericFooImplementor<>)
        .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}

[Test]
public void Should_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
    Assert.That(new GenericFooImplementor<string>().GetType()
        .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
}

[Test]
public void Should_not_inherit_or_implement_generic_interface_by_generic_subclass_not_caring_about_generic_type_parameter()
{
    Assert.That(new GenericFooImplementor<string>().GetType()
        .InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
}

[Test]
public void Should_inherit_or_implement_non_generic_class()
{
    Assert.That(typeof(FooImplementor)
        .InheritsOrImplements(typeof(FooBase)), Is.True);
}

[Test]
public void Should_inherit_or_implement_any_base_type()
{
    Assert.That(typeof(GenericFooImplementor<>)
        .InheritsOrImplements(typeof(FooBase)), Is.True);
}

2
मैं ResolveGenericTypeDefinition पद्धति के बारे में हैरान हूं। "ShouldUseGenericType" वैरिएबल को वास्तव में मान असाइन किया गया है: !parent.IsGenericType || parent.GetGenericTypeDefinition() == parent; इसलिए यदि आप उस वैरिएबल को प्रतिस्थापित करते हैं तो इफ स्टेटमेंट के विस्तार के साथ: if (parent.IsGenericType && shouldUseGenericType) और आपको वह मिल जाता है if (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent)) जो तब घटता है if (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
माइकल ब्लैकबर्न

2
जो कुछ नहीं करता प्रतीत होगा। यदि ये मूल्य प्रकार होते हैं जो int j = 0; if (j is an int && j == 0) { j=0; } मेरे संदर्भ के बराबर होते हैं तो क्या मैं अपने संदर्भ के बराबर होता हूं और मूल्य बराबर हो जाता है? मैंने सोचा था कि मेमोरी में प्रत्येक प्रकार का केवल एक उदाहरण था, इसलिए दो चर जो एक ही प्रकार को इंगित करते हैं, वास्तव में स्मृति में एक ही स्थान की ओर इशारा करते हैं।
माइकल ब्लैकबर्न

1
@MichaelBlackburn स्पॉट पर :) मैंने इसे सिर्फ इसलिए वापस ले लिया: माता-पिता को वापस करें। जेनरिकटाइप? parent.GetGenericTypeDefinition (): पैरेंट;
एरोनएचएस

3
अगर इसके पहले से ही माता पिता के रूप में, बस इसे वापस कर! और वह कई बार GetGenericTypeDef पर कॉल कर रहा है। इसे बस एक बार बुलाया जाना चाहिए
आरोनएचएस

1
क्षमा करें, मैं नीचे एक नई टिप्पणी जोड़ूंगा।
मेंनो डीज - वैन रिज्स्विज्क

26

यह मुझे लगता है कि यह कार्यान्वयन अधिक मामलों में काम करता है (सामान्य वर्ग और इंटरफ़ेस, आरंभिक मापदंडों के साथ या बिना, बच्चे और मापदंडों की संख्या के बिना):

public static class ReflexionExtension
{
    public static bool IsSubClassOfGeneric(this Type child, Type parent)
    {
        if (child == parent)
            return false;

        if (child.IsSubclassOf(parent))
            return true;

        var parameters = parent.GetGenericArguments();
        var isParameterLessGeneric = !(parameters != null && parameters.Length > 0 &&
            ((parameters[0].Attributes & TypeAttributes.BeforeFieldInit) == TypeAttributes.BeforeFieldInit));

        while (child != null && child != typeof(object))
        {
            var cur = GetFullTypeDefinition(child);
            if (parent == cur || (isParameterLessGeneric && cur.GetInterfaces().Select(i => GetFullTypeDefinition(i)).Contains(GetFullTypeDefinition(parent))))
                return true;
            else if (!isParameterLessGeneric)
                if (GetFullTypeDefinition(parent) == cur && !cur.IsInterface)
                {
                    if (VerifyGenericArguments(GetFullTypeDefinition(parent), cur))
                        if (VerifyGenericArguments(parent, child))
                            return true;
                }
                else
                    foreach (var item in child.GetInterfaces().Where(i => GetFullTypeDefinition(parent) == GetFullTypeDefinition(i)))
                        if (VerifyGenericArguments(parent, item))
                            return true;

            child = child.BaseType;
        }

        return false;
    }

    private static Type GetFullTypeDefinition(Type type)
    {
        return type.IsGenericType ? type.GetGenericTypeDefinition() : type;
    }

    private static bool VerifyGenericArguments(Type parent, Type child)
    {
        Type[] childArguments = child.GetGenericArguments();
        Type[] parentArguments = parent.GetGenericArguments();
        if (childArguments.Length == parentArguments.Length)
            for (int i = 0; i < childArguments.Length; i++)
                if (childArguments[i].Assembly != parentArguments[i].Assembly || childArguments[i].Name != parentArguments[i].Name || childArguments[i].Namespace != parentArguments[i].Namespace)
                    if (!childArguments[i].IsSubclassOf(parentArguments[i]))
                        return false;

        return true;
    }
}

यहाँ मेरे 70 76 परीक्षण मामले हैं:

[TestMethod]
public void IsSubClassOfGenericTest()
{
    Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 1");
    Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric<>)), " 2");
    Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), " 3");
    Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric<>)), " 4");
    Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), " 5");
    Assert.IsFalse(typeof(IWrongBaseGeneric<>).IsSubClassOfGeneric(typeof(ChildGeneric2<>)), " 6");
    Assert.IsTrue(typeof(ChildGeneric2<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 7");
    Assert.IsTrue(typeof(ChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), " 8");
    Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), " 9");
    Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(WrongBaseGeneric<Class1>)), "10");
    Assert.IsTrue(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "11");
    Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(IWrongBaseGeneric<Class1>)), "12");
    Assert.IsTrue(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "13");
    Assert.IsFalse(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(ChildGeneric2<Class1>)), "14");
    Assert.IsTrue(typeof(ChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), "15");
    Assert.IsFalse(typeof(ChildGeneric).IsSubClassOfGeneric(typeof(ChildGeneric)), "16");
    Assert.IsFalse(typeof(IChildGeneric).IsSubClassOfGeneric(typeof(IChildGeneric)), "17");
    Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(IChildGeneric2<>)), "18");
    Assert.IsTrue(typeof(IChildGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "19");
    Assert.IsTrue(typeof(IChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "20");
    Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IChildGeneric2<Class1>)), "21");
    Assert.IsTrue(typeof(IChildGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "22");
    Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(BaseGeneric<Class1>)), "23");
    Assert.IsTrue(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "24");
    Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric<>)), "25");
    Assert.IsTrue(typeof(BaseGeneric<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "26");
    Assert.IsTrue(typeof(BaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "27");
    Assert.IsFalse(typeof(IBaseGeneric<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "28");
    Assert.IsTrue(typeof(BaseGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<Class1>)), "29");
    Assert.IsFalse(typeof(IBaseGeneric<>).IsSubClassOfGeneric(typeof(BaseGeneric2<>)), "30");
    Assert.IsTrue(typeof(BaseGeneric2<>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "31");
    Assert.IsTrue(typeof(BaseGeneric2<Class1>).IsSubClassOfGeneric(typeof(IBaseGeneric<>)), "32");
    Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "33");
    Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA<,>)), "34");
    Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "35");
    Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA<,>)), "36");
    Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "37");
    Assert.IsFalse(typeof(IWrongBaseGenericA<,>).IsSubClassOfGeneric(typeof(ChildGenericA2<,>)), "38");
    Assert.IsTrue(typeof(ChildGenericA2<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "39");
    Assert.IsTrue(typeof(ChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "40");
    Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "41");
    Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(WrongBaseGenericA<ClassA, ClassB>)), "42");
    Assert.IsTrue(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "43");
    Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(IWrongBaseGenericA<ClassA, ClassB>)), "44");
    Assert.IsTrue(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "45");
    Assert.IsFalse(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(ChildGenericA2<ClassA, ClassB>)), "46");
    Assert.IsTrue(typeof(ChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "47");
    Assert.IsFalse(typeof(ChildGenericA).IsSubClassOfGeneric(typeof(ChildGenericA)), "48");
    Assert.IsFalse(typeof(IChildGenericA).IsSubClassOfGeneric(typeof(IChildGenericA)), "49");
    Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(IChildGenericA2<,>)), "50");
    Assert.IsTrue(typeof(IChildGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "51");
    Assert.IsTrue(typeof(IChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "52");
    Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IChildGenericA2<ClassA, ClassB>)), "53");
    Assert.IsTrue(typeof(IChildGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "54");
    Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "55");
    Assert.IsTrue(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "56");
    Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA<,>)), "57");
    Assert.IsTrue(typeof(BaseGenericA<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "58");
    Assert.IsTrue(typeof(BaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "59");
    Assert.IsFalse(typeof(IBaseGenericA<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "60");
    Assert.IsTrue(typeof(BaseGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "61");
    Assert.IsFalse(typeof(IBaseGenericA<,>).IsSubClassOfGeneric(typeof(BaseGenericA2<,>)), "62");
    Assert.IsTrue(typeof(BaseGenericA2<,>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "63");
    Assert.IsTrue(typeof(BaseGenericA2<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericA<,>)), "64");
    Assert.IsFalse(typeof(BaseGenericA2<ClassB, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericA<ClassA, ClassB>)), "65");
    Assert.IsFalse(typeof(BaseGenericA<ClassB, ClassA>).IsSubClassOfGeneric(typeof(ChildGenericA2<ClassA, ClassB>)), "66");
    Assert.IsFalse(typeof(BaseGenericA2<ClassB, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericA<ClassA, ClassB>)), "67");
    Assert.IsTrue(typeof(ChildGenericA3<ClassA, ClassB>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68");
    Assert.IsTrue(typeof(ChildGenericA4<ClassA, ClassB>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69");
    Assert.IsFalse(typeof(ChildGenericA3<ClassB, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-2");
    Assert.IsTrue(typeof(ChildGenericA3<ClassA, ClassB2>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-3");
    Assert.IsFalse(typeof(ChildGenericA3<ClassB2, ClassA>).IsSubClassOfGeneric(typeof(BaseGenericB<ClassA, ClassB, ClassC>)), "68-4");
    Assert.IsFalse(typeof(ChildGenericA4<ClassB, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-2");
    Assert.IsTrue(typeof(ChildGenericA4<ClassA, ClassB2>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-3");
    Assert.IsFalse(typeof(ChildGenericA4<ClassB2, ClassA>).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "69-4");
    Assert.IsFalse(typeof(bool).IsSubClassOfGeneric(typeof(IBaseGenericB<ClassA, ClassB, ClassC>)), "70");
}

परीक्षण के लिए कक्षाएं और इंटरफेस:

public class Class1 { }
public class BaseGeneric<T> : IBaseGeneric<T> { }
public class BaseGeneric2<T> : IBaseGeneric<T>, IInterfaceBidon { }
public interface IBaseGeneric<T> { }
public class ChildGeneric : BaseGeneric<Class1> { }
public interface IChildGeneric : IBaseGeneric<Class1> { }
public class ChildGeneric2<Class1> : BaseGeneric<Class1> { }
public interface IChildGeneric2<Class1> : IBaseGeneric<Class1> { }

public class WrongBaseGeneric<T> { }
public interface IWrongBaseGeneric<T> { }

public interface IInterfaceBidon { }

public class ClassA { }
public class ClassB { }
public class ClassC { }
public class ClassB2 : ClassB { }
public class BaseGenericA<T, U> : IBaseGenericA<T, U> { }
public class BaseGenericB<T, U, V> { }
public interface IBaseGenericB<ClassA, ClassB, ClassC> { }
public class BaseGenericA2<T, U> : IBaseGenericA<T, U>, IInterfaceBidonA { }
public interface IBaseGenericA<T, U> { }
public class ChildGenericA : BaseGenericA<ClassA, ClassB> { }
public interface IChildGenericA : IBaseGenericA<ClassA, ClassB> { }
public class ChildGenericA2<ClassA, ClassB> : BaseGenericA<ClassA, ClassB> { }
public class ChildGenericA3<ClassA, ClassB> : BaseGenericB<ClassA, ClassB, ClassC> { }
public class ChildGenericA4<ClassA, ClassB> : IBaseGenericB<ClassA, ClassB, ClassC> { }
public interface IChildGenericA2<ClassA, ClassB> : IBaseGenericA<ClassA, ClassB> { }

public class WrongBaseGenericA<T, U> { }
public interface IWrongBaseGenericA<T, U> { }

public interface IInterfaceBidonA { }

4
यह एकमात्र समाधान है जिसने मेरे लिए काम किया। मैं उन वर्गों के साथ काम करने वाला कोई अन्य समाधान नहीं खोज सका जिनके पास कई प्रकार के पैरामीटर हैं। धन्यवाद।
कॉनर क्लार्क

1
मैंने वास्तव में आपके इन सभी परीक्षण मामलों की सराहना की है। मुझे लगता है कि 68 और 69 के मामले सही होने के बजाय झूठे होने चाहिए, क्योंकि आपके पास क्लासबी है, बाईं तरफ क्लासए और क्लासए, क्लासबी सही है।
ग्रैक्स 32

आप ठीक कह रहे हैं, @Grax। मेरे पास अभी सुधार करने का समय नहीं है, लेकिन जैसे ही यह किया जाएगा मैं अपनी पोस्ट को अपडेट कर दूंगा। मुझे लगता है कि सुधार "
VerifyGenericArguments

1
@ ग्रेक्स: मुझे सुधार करने के लिए कुछ समय मिला। मैंने ClassB2 वर्ग जोड़ा, मैंने VerifyGenericArguments को बदल दिया, और मैंने VerifyGenericArguments के कॉल पर एक नियंत्रण जोड़ा। मैंने 68 और 69 मामलों को भी संशोधित किया और 68-2, 68-3, 68-4, 69-2, 69-3 और 69-4 को जोड़ा।
Xav987

1
धन्यवाद महोदय। काम के समाधान के लिए +1 और परीक्षण मामलों की जबरदस्त मात्रा (मेरे लिए जबरदस्त, कम से कम)।
एल्डोआर

10

JaredPar का कोड काम करता है लेकिन केवल एक स्तर की विरासत के लिए। विरासत के असीमित स्तरों के लिए, निम्नलिखित कोड का उपयोग करें

public bool IsTypeDerivedFromGenericType(Type typeToCheck, Type genericType)
{
    if (typeToCheck == typeof(object))
    {
        return false;
    }
    else if (typeToCheck == null)
    {
        return false;
    }
    else if (typeToCheck.IsGenericType && typeToCheck.GetGenericTypeDefinition() == genericType)
    {
        return true;
    }
    else
    {
        return IsTypeDerivedFromGenericType(typeToCheck.BaseType, genericType);
    }
}

4
whileJaredPar के कोड में असीमित स्तरों को शामिल किया गया।
जे।

@ संजय ... और पुनरावृत्ति से बचा जाता है।
मार्क एल।

1
@MarcL। यह पूंछ पुनर्संरचना का उपयोग करता है, इसलिए संकलक को पुनरावृत्ति को अनुकूलित करने के लिए यह तुच्छ होना चाहिए।
दारुकुक

10

यहाँ मैंने जाँच के लिए एक छोटा सा तरीका बनाया है कि एक वस्तु एक विशिष्ट प्रकार से ली गई है। मेरे लिए महान काम करता है!

internal static bool IsDerivativeOf(this Type t, Type typeToCompare)
{
    if (t == null) throw new NullReferenceException();
    if (t.BaseType == null) return false;

    if (t.BaseType == typeToCompare) return true;
    else return t.BaseType.IsDerivativeOf(typeToCompare);
}

7

यह ओवरकिल हो सकता है लेकिन मैं निम्नलिखित की तरह विस्तार विधियों का उपयोग करता हूं। वे इंटरफेस के साथ-साथ उपवर्गों की जांच करते हैं। यह उस प्रकार को भी लौटा सकता है जिसमें निर्दिष्ट सामान्य परिभाषा है।

उदाहरण के लिए प्रश्न में यह सामान्य इंटरफ़ेस के साथ-साथ सामान्य वर्ग के खिलाफ परीक्षण कर सकता है। लौटे प्रकार का उपयोग GetGenericArgumentsयह निर्धारित करने के लिए किया जा सकता है कि सामान्य तर्क प्रकार "SomeType" है।

/// <summary>
/// Checks whether this type has the specified definition in its ancestry.
/// </summary>   
public static bool HasGenericDefinition(this Type type, Type definition)
{
    return GetTypeWithGenericDefinition(type, definition) != null;
}

/// <summary>
/// Returns the actual type implementing the specified definition from the
/// ancestry of the type, if available. Else, null.
/// </summary>
public static Type GetTypeWithGenericDefinition(this Type type, Type definition)
{
    if (type == null)
        throw new ArgumentNullException("type");
    if (definition == null)
        throw new ArgumentNullException("definition");
    if (!definition.IsGenericTypeDefinition)
        throw new ArgumentException(
            "The definition needs to be a GenericTypeDefinition", "definition");

    if (definition.IsInterface)
        foreach (var interfaceType in type.GetInterfaces())
            if (interfaceType.IsGenericType
                && interfaceType.GetGenericTypeDefinition() == definition)
                return interfaceType;

    for (Type t = type; t != null; t = t.BaseType)
        if (t.IsGenericType && t.GetGenericTypeDefinition() == definition)
            return t;

    return null;
}

अच्छी पोस्ट! चिंताओं को दो तरीकों से विभाजित करके अच्छा लगा।
विएब तिजमा

4

Fir3rpho3nixx और डेविड श्मिट द्वारा ऊपर दिए गए उत्कृष्ट उत्तर पर बिल्डिंग, मैंने उनके कोड को संशोधित किया है और ShouldInheritOrImplementTypedGenericInterface परीक्षण (पिछले एक) को जोड़ा है।

    /// <summary>
    /// Find out if a child type implements or inherits from the parent type.
    /// The parent type can be an interface or a concrete class, generic or non-generic.
    /// </summary>
    /// <param name="child"></param>
    /// <param name="parent"></param>
    /// <returns></returns>
    public static bool InheritsOrImplements(this Type child, Type parent)
    {
        var currentChild = parent.IsGenericTypeDefinition && child.IsGenericType ? child.GetGenericTypeDefinition() : child;

        while (currentChild != typeof(object))
        {
            if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
                return true;

            currentChild = currentChild.BaseType != null && parent.IsGenericTypeDefinition && currentChild.BaseType.IsGenericType
                                ? currentChild.BaseType.GetGenericTypeDefinition()
                                : currentChild.BaseType;

            if (currentChild == null)
                return false;
        }
        return false;
    }

    private static bool HasAnyInterfaces(Type parent, Type child)
    {
        return child.GetInterfaces().Any(childInterface =>
            {
                var currentInterface = parent.IsGenericTypeDefinition && childInterface.IsGenericType
                    ? childInterface.GetGenericTypeDefinition()
                    : childInterface;

                return currentInterface == parent;
            });

    }

    [Test]
    public void ShouldInheritOrImplementNonGenericInterface()
    {
        Assert.That(typeof(FooImplementor)
            .InheritsOrImplements(typeof(IFooInterface)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterface()
    {
        Assert.That(typeof(GenericFooBase)
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterfaceByGenericSubclass()
    {
        Assert.That(typeof(GenericFooImplementor<>)
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
    {
        Assert.That(new GenericFooImplementor<string>().GetType()
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldNotInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
    {
        Assert.That(new GenericFooImplementor<string>().GetType()
            .InheritsOrImplements(typeof(IGenericFooInterface<int>)), Is.False);
    }

    [Test]
    public void ShouldInheritOrImplementNonGenericClass()
    {
        Assert.That(typeof(FooImplementor)
            .InheritsOrImplements(typeof(FooBase)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementAnyBaseType()
    {
        Assert.That(typeof(GenericFooImplementor<>)
            .InheritsOrImplements(typeof(FooBase)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementTypedGenericInterface()
    {
        GenericFooImplementor<int> obj = new GenericFooImplementor<int>();
        Type t = obj.GetType();

        Assert.IsTrue(t.InheritsOrImplements(typeof(IGenericFooInterface<int>)));
        Assert.IsFalse(t.InheritsOrImplements(typeof(IGenericFooInterface<String>)));
    } 

4

यह सब आसानी से linq के साथ किया जा सकता है। यह किसी भी प्रकार का मिलेगा जो जेनेरिक बेस क्लास GenericBaseType का उपवर्ग है।

    IEnumerable<Type> allTypes = Assembly.GetExecutingAssembly().GetTypes();

    IEnumerable<Type> mySubclasses = allTypes.Where(t => t.BaseType != null 
                                                            && t.BaseType.IsGenericType
                                                            && t.BaseType.GetGenericTypeDefinition() == typeof(GenericBaseType<,>));

यह एकमात्र समाधान था जिसने मेरे लिए काम किया। सरल और सुरुचिपूर्ण। धन्यवाद।
सिल्कफेयर

4

सरल समाधान: जेनेरिक क्लास में एक दूसरा, गैर-जेनेरिक इंटरफ़ेस बनाएं और जोड़ें:

public interface IGenericClass
{
}

public class GenericClass<T> : GenericInterface<T>, IGenericClass
{
}

तो फिर सिर्फ इतना है कि किसी भी तरह से आप का उपयोग कर पसंद के लिए जाँच is, as, IsAssignableFrom, आदि

if (thing is IGenericClass)
{
    // Do work
{

स्पष्ट रूप से केवल तभी संभव है जब आपके पास जेनेरिक क्लास (जो ओपी लगता है) को संपादित करने की क्षमता है, लेकिन यह एक गुप्त विस्तार विधि का उपयोग करने से थोड़ा अधिक सुरुचिपूर्ण और पठनीय है।


1
हालाँकि, यह जाँचना कि क्या कुछ प्रकार का है, IGenericClassआपको इसकी गारंटी नहीं देगा GenericClassया GenericInterfaceवास्तव में विस्तारित या कार्यान्वित किया जाएगा। इसका अर्थ है, आपका कंपाइलर आपको सामान्य वर्ग के किसी भी सदस्य तक पहुँचने की अनुमति नहीं देगा।
B12Toaster 20

4

@ Jaredpar के जवाब में जोड़ा गया, यहाँ मैं इंटरफेस के लिए जाँच करने के लिए क्या उपयोग करता हूँ:

public static bool IsImplementerOfRawGeneric(this Type type, Type toCheck)
{
    if (toCheck.GetTypeInfo().IsClass)
    {
        return false;
    }

    return type.GetInterfaces().Any(interfaceType =>
    {
        var current = interfaceType.GetTypeInfo().IsGenericType ?
                    interfaceType.GetGenericTypeDefinition() : interfaceType;
        return current == toCheck;
    });
}

public static bool IsSubTypeOfRawGeneric(this Type type, Type toCheck)
{
    return type.IsInterface ?
          IsImplementerOfRawGeneric(type, toCheck)
        : IsSubclassOfRawGeneric(type, toCheck);
}

उदाहरण के लिए:

Console.WriteLine(typeof(IList<>).IsSubTypeOfRawGeneric(typeof(IList<int>))); // true

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

@ टोनी, टिप के लिए धन्यवाद, लेकिन अगली बार जवाब अपडेट करें।
जॉनी 5

@vexe, परीक्षण महत्वपूर्ण है कि आपका मूल उत्तर टूट गया है, यह केवल इसलिए काम करता है क्योंकि आपने इसे इंटरफ़ेस पर परीक्षण किया है। दूसरी बात, आप इस प्रकार की परवाह किए बिना इस फ़ंक्शन को चलाकर प्रोसेसिंग पावर बर्बाद कर रहे हैं।
जॉनी 5

2

JaredPar,

यह मेरे लिए काम नहीं किया अगर मैं टाइपऑफ़ पास (टाइप <>) के रूप में जाँच करें। यहाँ मैं क्या बदल गया है।

static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
    while (toCheck != typeof(object)) {
        var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
          if (cur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()) {
            return true;
        }
        toCheck = toCheck.BaseType;
    }
    return false;
}

JaredPar के समाधान वास्तव में के लिए काम करता typeof(type<>)के रूप में toCheck। इसके अलावा आपको वास्तव में जारेडपर के समाधान के रूप में अशक्त जांच की आवश्यकता है। इसके अलावा, मुझे नहीं पता कि आप केवल अन्य सामान्य प्रकारों के लिए काम करने के लिए अपने तरीके को प्रतिबंधित करने के अलावा cur == genericउसके समाधान में क्या बदल रहे हैं cur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()। दूसरे शब्दों में, इस तरह कुछ भी एक अपवाद के साथ विफल:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
nawfal

2

@EnocNRoll - आनंद गोपाल का जवाब दिलचस्प है, लेकिन अगर कोई उदाहरण पहले से त्वरित नहीं है या आप एक सामान्य प्रकार की परिभाषा के साथ जांच करना चाहते हैं, तो मैं इस विधि का सुझाव दूंगा:

public static bool TypeIs(this Type x, Type d) {
    if(null==d) {
        return false;
    }

    for(var c = x; null!=c; c=c.BaseType) {
        var a = c.GetInterfaces();

        for(var i = a.Length; i-->=0;) {
            var t = i<0 ? c : a[i];

            if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
                return true;
            }
        }
    }

    return false;
}

और इसका उपयोग करें:

var b = typeof(char[]).TypeIs(typeof(IList<>)); // true

जब दोनों चार सशर्त मामलों रहे हैं t(परीक्षण किया जाना) और dसामान्य प्रकार के होते हैं और दो मामलों कवर कर रहे हैं द्वारा t==dजो कर रहे हैं (1) न tहै और न ही dएक सामान्य परिभाषा है या (2) उन दोनों को सामान्य परिभाषाएं दी गई हैं । बाकी मामलों रहे हैं उनमें से एक एक सामान्य परिभाषा है, केवल जब dपहले से ही एक सामान्य परिभाषा हम कहने के लिए मौका है है एक tएक हैd लेकिन ठीक इसके विपरीत।

यह मनमाने ढंग से कक्षाओं या इंटरफेस के साथ काम करना चाहिए जिसे आप परीक्षण करना चाहते हैं, और यदि आप isऑपरेटर के साथ उस प्रकार की एक आवृत्ति का परीक्षण करते हैं तो क्या होगा ।


0
Type _type = myclass.GetType();
PropertyInfo[] _propertyInfos = _type.GetProperties();
Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition() 
== typeof(List<>);

0

आप इस एक्सटेंशन को आज़मा सकते हैं

    public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t)
    {
        return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t }));
    }

0

इस खेल में देर हो चुकी है ... मैं भी अभी तक JarodPar के जवाब का एक और क्रमांकन हूं।

यहाँ प्रकार: .sSubClassOf (प्रकार) परावर्तक के सौजन्य से:

    public virtual bool IsSubclassOf(Type c)
    {
        Type baseType = this;
        if (!(baseType == c))
        {
            while (baseType != null)
            {
                if (baseType == c)
                {
                    return true;
                }
                baseType = baseType.BaseType;
            }
            return false;
        }
        return false;
    }

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

    public static bool IsExtension(this Type thisType, Type potentialSuperType)
    {
        //
        // protect ya neck
        //
        if (thisType == null || potentialSuperType == null || thisType == potentialSuperType) return false;

        //
        // don't need to traverse inheritance for interface extension, so check/do these first
        //
        if (potentialSuperType.IsInterface)
        {
            foreach (var interfaceType in thisType.GetInterfaces())
            {
                var tempType = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType;

                if (tempType == potentialSuperType)
                {
                    return true;
                }
            }
        }

        //
        // do the concrete type checks, iterating up the inheritance chain, as in orignal
        //
        while (thisType != null && thisType != typeof(object))
        {
            var cur = thisType.IsGenericType ? thisType.GetGenericTypeDefinition() : thisType;

            if (potentialSuperType == cur)
            {
                return true;
            }

            thisType = thisType.BaseType;
        }
        return false;
    }

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

  1. सामान्य "एक्सटेंशन" तक खुला है - मैं विरासत (विचार वर्गों) के साथ-साथ कार्यान्वयन (इंटरफेस) पर विचार कर रहा हूं; इसे बेहतर ढंग से दर्शाने के लिए विधि और पैरामीटर नाम बदले जाते हैं
  2. इनपुट शून्य-मान्यता (हाँ)
  3. एक ही प्रकार का इनपुट (एक वर्ग स्वयं का विस्तार नहीं कर सकता)
  4. शॉर्ट सर्किट निष्पादन यदि प्रश्न में प्रकार एक इंटरफ़ेस है; क्योंकि GetInterfaces () सभी लागू किए गए इंटरफ़ेस (यहां तक ​​कि सुपर-क्लास में लागू किए गए) लौटाता है, आप बस उस संग्रह के माध्यम से लूप कर सकते हैं जिसमें विरासत के पेड़ पर चढ़ना नहीं है

बाकी मूल रूप से JaredPar के कोड के समान है

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