यह निर्धारित करने के लिए कि यदि कोई प्रकार एक विशिष्ट सामान्य इंटरफ़ेस प्रकार लागू करता है


226

निम्नलिखित प्रकार की परिभाषाएँ मानें:

public interface IFoo<T> : IBar<T> {}
public class Foo<T> : IFoo<T> {}

मुझे कैसे पता चलेगा कि क्या प्रकार केवल Fooसामान्य IBar<T>प्रकार के उपलब्ध होने पर सामान्य इंटरफ़ेस को लागू करता है?

जवाबों:


387

TcK से उत्तर का उपयोग करके यह निम्नलिखित LINQ क्वेरी के साथ भी किया जा सकता है:

bool isBar = foo.GetType().GetInterfaces().Any(x =>
  x.IsGenericType &&
  x.GetGenericTypeDefinition() == typeof(IBar<>));

1
यह एक बहुत ही सुंदर समाधान है! जिन लोगों को मैंने SO पर देखा है, वे फ़ॉरच लूप या लंबे समय तक LINQ क्वेरी का उपयोग करते हैं। हालांकि ध्यान रखें कि इसका उपयोग करने के लिए, आपके पास .NET फ्रेमवर्क 3.5 होना चाहिए।
डैनियल टी।

7
मेरा सुझाव है कि आप इसे एक विस्तार विधि बनाने के लिए एक la.ly/ccza8B - यह काफी अच्छी तरह से साफ करेंगे!
ब्रैड हेलर

1
अपनी आवश्यकताओं के आधार पर, आप पा सकते हैं कि आपको दिए गए इंटरफेस पर पुनरावृत्ति करने की आवश्यकता है।
सेबस्टियन अच्छा

4
मैं कहता हूं कि इसे .net के भीतर बेहतर तरीके से लागू किया जाना चाहिए ... एक कोर के रूप में ... जैसे कि सदस्य ।mplements (IBar) या CustomType.Implements (IBAR), या इससे भी बेहतर, एक कीवर्ड "" का उपयोग कर रहा है। .. मैं c # को खोज रहा हूं और अभी मैं थोड़ा और निराश हूं। अभी अभी ...
Sofija

2
मामूली जोड़: यदि आईबीएआर के कई सामान्य प्रकार हैं, तो आपको यह इंगित करने की आवश्यकता है: typeof(IBar<,,,>)प्लेसहोल्डर्स की तरह अल्पविराम अभिनय के साथ
रोब वॉन नेसलरोड

33

आपको वंशानुक्रम वृक्ष के माध्यम से ऊपर जाना होगा और पेड़ में प्रत्येक वर्ग के लिए सभी इंटरफेस खोजने होंगे, और यदि इंटरफ़ेस सामान्य है तोtypeof(IBar<>) कॉलिंग के परिणाम की तुलना करें । यह सब थोड़ा दर्दनाक है, निश्चित रूप से।Type.GetGenericTypeDefinition

देखें क्या यह उत्तर और इन लोगों को अधिक जानकारी और कोड के लिए।


सिर्फ IBar <SomeClass> को ही क्यों न डालें और अशक्त के लिए जाँच करें? (मेरा मतलब है 'के रूप में' के साथ कास्टिंग)
पाब्लो Retyk

5
टी अज्ञात है और एक विशिष्ट प्रकार के लिए नहीं डाली जा सकती है।
sduplooy

@ sduplooy: शायद मुझे कुछ याद आ रहा है कि T अज्ञात कैसे हो सकता है? यह सार्वजनिक वर्ग फू को संकलित करेगा: इफू <टी> {}
पाब्लो रिटेल

25
public interface IFoo<T> : IBar<T> {}
public class Foo : IFoo<Foo> {}

var implementedInterfaces = typeof( Foo ).GetInterfaces();
foreach( var interfaceType in implementedInterfaces ) {
    if ( false == interfaceType.IsGeneric ) { continue; }
    var genericType = interfaceType.GetGenericTypeDefinition();
    if ( genericType == typeof( IFoo<> ) ) {
        // do something !
        break;
    }
}

2
चूंकि टाइपऑफ़ (फू) एक System.Type ऑब्जेक्ट (Foo का वर्णन करता है) लौटाता है, GetType () कॉल हमेशा System.Type के प्रकार को लौटाएगा। आपको टाइपोफ (फू) .गेटइंटरफ़ेसेस () में बदलना चाहिए
माइकल

9

एक सहायक विधि विस्तार के रूप में

public static bool Implements<I>(this Type type, I @interface) where I : class
{
    if(((@interface as Type)==null) || !(@interface as Type).IsInterface)
        throw new ArgumentException("Only interfaces can be 'implemented'.");

    return (@interface as Type).IsAssignableFrom(type);
}

उदाहरण का उपयोग:

var testObject = new Dictionary<int, object>();
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true!

2
"IsAssignableFrom" बिल्कुल वही था जिसकी मैं तलाश कर रहा था - धन्यवाद
जेसपर

22
यह सामान्य प्रकार के पैरामीटर को न जानने के लिए पूछने वाले की आवश्यकता के लिए काम नहीं करता है। अपने उदाहरण से testObject.GetType ()। इम्प्लीमेंट्स (टाइपोफ़ (IDEDIA <,>)); झूठा लौटेगा।
ctusch

@ctusch तो, उसके लिए कोई उपाय?
Tohid

5

मैं @GenericProgrammers एक्सटेंशन विधि का थोड़ा सरल संस्करण उपयोग कर रहा हूं:

public static bool Implements<TInterface>(this Type type) where TInterface : class {
    var interfaceType = typeof(TInterface);

    if (!interfaceType.IsInterface)
        throw new InvalidOperationException("Only interfaces can be implemented.");

    return (interfaceType.IsAssignableFrom(type));
}

उपयोग:

    if (!featureType.Implements<IFeature>())
        throw new InvalidCastException();

5
यह अभी भी मूल प्रश्न की आवश्यकता के अनुसार काम नहीं करता है जो सामान्य इंटरफेस के लिए है।
nathanchere

4

आपको जेनेरिक इंटरफ़ेस के निर्माण प्रकार के खिलाफ जांच करनी होगी।

आपको कुछ इस तरह करना होगा:

foo is IBar<String>

क्योंकि IBar<String>उस प्रकार का प्रतिनिधित्व करता है। ऐसा करने का कारण यह है कि यदि Tआपके चेक में अपरिभाषित है, तो संकलक को पता नहीं है कि आपका क्या मतलब है IBar<Int32>या IBar<SomethingElse>


4

पूरी तरह से प्रकार प्रणाली से निपटने के लिए, मैं तुम्हें संभाल प्रत्यावर्तन, जैसे की जरूरत है लगता है IList<T>: ICollection<T>: IEnumerable<T>, जिसके बिना आप नहीं जानते हैं कि IList<int>अंततः औजार IEnumerable<>

    /// <summary>Determines whether a type, like IList&lt;int&gt;, implements an open generic interface, like
    /// IEnumerable&lt;&gt;. Note that this only checks against *interfaces*.</summary>
    /// <param name="candidateType">The type to check.</param>
    /// <param name="openGenericInterfaceType">The open generic type which it may impelement</param>
    /// <returns>Whether the candidate type implements the open interface.</returns>
    public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType)
    {
        Contract.Requires(candidateType != null);
        Contract.Requires(openGenericInterfaceType != null);

        return
            candidateType.Equals(openGenericInterfaceType) ||
            (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) ||
            candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType));

    }

3

सबसे पहले public class Foo : IFoo<T> {}संकलन नहीं करता है क्योंकि आपको टी के बजाय एक वर्ग निर्दिष्ट करने की आवश्यकता है, लेकिन यह मानते हुए कि आप कुछ ऐसा करते हैंpublic class Foo : IFoo<SomeClass> {}

यदि आप करते हैं तो

Foo f = new Foo();
IBar<SomeClass> b = f as IBar<SomeClass>;

if(b != null)  //derives from IBar<>
    Blabla();

2

यदि आप एक विस्तार विधि चाहते हैं जो सामान्य आधार प्रकारों के साथ-साथ इंटरफेस का समर्थन करेगी, तो मैंने sduplooy के उत्तर का विस्तार किया है:

    public static bool InheritsFrom(this Type t1, Type t2)
    {
        if (null == t1 || null == t2)
            return false;

        if (null != t1.BaseType &&
            t1.BaseType.IsGenericType &&
            t1.BaseType.GetGenericTypeDefinition() == t2)
        {
            return true;
        }

        if (InheritsFrom(t1.BaseType, t2))
            return true;

        return
            (t2.IsAssignableFrom(t1) && t1 != t2)
            ||
            t1.GetInterfaces().Any(x =>
              x.IsGenericType &&
              x.GetGenericTypeDefinition() == t2);
    }

1

यह जाँचने का तरीका कि क्या प्रकार विरासत में मिलता है या लागू होता है:

   public static bool IsTheGenericType(this Type candidateType, Type genericType)
    {
        return
            candidateType != null && genericType != null &&
            (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType ||
             candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) ||
             candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType));
    }

0

निम्नलिखित विस्तार का प्रयास करें।

public static bool Implements(this Type @this, Type @interface)
{
    if (@this == null || @interface == null) return false;
    return @interface.GenericTypeArguments.Length>0
        ? @interface.IsAssignableFrom(@this)
        : @this.GetInterfaces().Any(c => c.Name == @interface.Name);
}

इसका परीक्षण करना है। सृजन करना

public interface IFoo { }
public interface IFoo<T> : IFoo { }
public interface IFoo<T, M> : IFoo<T> { }
public class Foo : IFoo { }
public class Foo<T> : IFoo { }
public class Foo<T, M> : IFoo<T> { }
public class FooInt : IFoo<int> { }
public class FooStringInt : IFoo<string, int> { }
public class Foo2 : Foo { }

और परीक्षण विधि

public void Test()
{
    Console.WriteLine(typeof(Foo).Implements(typeof(IFoo)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<int>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<string>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<,>)));
    Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<,>)));
    Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<string,int>)));
    Console.WriteLine(typeof(Foo<int,string>).Implements(typeof(IFoo<string>)));
 }

-1

निम्नलिखित में कुछ भी गलत नहीं होना चाहिए:

bool implementsGeneric = (anObject.Implements("IBar`1") != null);

अतिरिक्त क्रेडिट के लिए आप AmbiguousMatchException को पकड़ सकते हैं यदि आप अपने IBar क्वेरी के साथ एक विशिष्ट सामान्य-प्रकार-पैरामीटर प्रदान करना चाहते हैं।


खैर, आमतौर पर जब संभव हो तो स्ट्रिंग शाब्दिक का उपयोग करने से बचना बेहतर होता है। इस दृष्टिकोण से एप्लिकेशन को फिर से भरना मुश्किल हो जाता है, क्योंकि IBAR इंटरफ़ेस का नाम बदलने से स्ट्रिंग शाब्दिक नहीं बदलेगा, और त्रुटि केवल रनटाइम में पता लगाने योग्य होगी।
andyroschy

जैसा कि मैं आमतौर पर 'मैजिक स्ट्रिंग्स' आदि का उपयोग करने के लिए ऊपर दिए गए टिप्पणी से सहमत हूं, यह अभी भी मुझे मिला सबसे अच्छा तरीका है। अच्छी तरह से पर्याप्त पास - PropertyType.Name के लिए परीक्षण "IWhatever`1" के बराबर।
nathanchere

यह क्यों नहीं? bool implementsGeneric = (anObject.Implements(typeof(IBar<>).Name) != null);
मैक्सिम गेलिनस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.