2009-02-02 16 views
174

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

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

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

उत्तर

306

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

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

यह एक बहुत ही सुरुचिपूर्ण समाधान है! एसओ पर मैंने जो कुछ देखा है, वह फोरैच लूप या लंबे LINQ प्रश्नों का उपयोग करता है। ध्यान रखें कि इसका उपयोग करने के लिए, आपको .NET Framework 3.5 होना चाहिए। –

+7

मुझे सलाह है कि आप इसे एक विस्तार विधि ला लाएं http://bit.ly/ccza8B - इसे काफी अच्छी तरह साफ कर देगा! –

+1

आपकी ज़रूरतों के आधार पर, आपको लगता है कि आपको वापस आने वाले इंटरफेस पर दोबारा उपयोग करने की आवश्यकता है। –

4

आपको जेनेरिक इंटरफेस के एक निर्मित प्रकार के खिलाफ जांच करनी है।

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

foo is IBar<String> 

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

31

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

अधिक जानकारी और कोड के लिए this answer और these ones देखें।

+0

क्यों न सिर्फ इबार पर डाला गया और शून्य की जांच करें? (मेरा मतलब है 'निश्चित रूप से' के रूप में कास्टिंग) –

+3

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

+0

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

19
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; 
    } 
} 
+1

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

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(); 
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" बिल्कुल वही था जो मैं ढूंढ रहा था - धन्यवाद – Jesper

+14

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

4

मैं @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(); 
+3

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

0

अतिरिक्त क्रेडिट के लिए आप AmbiguousMatchException पकड़ सकते थे यदि आप किसी विशिष्ट अपने Ibar क्वेरी के साथ सामान्य प्रकार पैरामीटर देना चाहते थे: 210 वहाँ कुछ भी गलत निम्नलिखित नहीं होना चाहिए।

+0

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

+0

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

+0

ऐसा क्यों नहीं? 'बूल इम्प्लेमेंट्स जेनेरिक = (anObject.Implements (टाइपऑफ (आईबीआर <>)। नाम)! = शून्य); ' –

3

पूरी तरह से प्रकार प्रणाली से निपटने के लिए, मैं आप प्रत्यावर्तन को संभालने के लिए, उदाहरण के लिए की जरूरत है 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)); 

    } 
1

मामले आप एक विस्तार विधि है कि जेनेरिक आधार प्रकार के साथ-साथ इंटरफेस का समर्थन चाहते थे में, मैं विस्तार किया है 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)); 
    } 
संबंधित मुद्दे