यह निर्धारित करने के लिए कि कोई प्रकार C # परावर्तन के साथ एक इंटरफ़ेस लागू करता है


561

है प्रतिबिंब में C#अगर कुछ दिया निर्धारित करने के लिए प्रस्ताव के लिए एक रास्ता System.Typeप्रकार मॉडल कुछ इंटरफेस?

public interface IMyInterface {}

public class MyType : IMyInterface {}

// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);

जवाबों:


968

आपके पास कुछ विकल्प हैं:

  1. typeof(IMyInterface).IsAssignableFrom(typeof(MyType))

  2. typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))

एक सामान्य इंटरफ़ेस के लिए, यह थोड़ा अलग है।

typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))

68
याद रखें कि टाइपोफ़ (IMyInterface) .IsAssignableFrom (टाइपोफ़ (IMyInterface)) भी सत्य है, जिसका आपके कोड पर अप्रत्याशित परिणाम हो सकता है।
क्रिस केम्प

29
यह सुनिश्चित करना आसान था कि ध्यान न दें और IsAssignableFromपीछे की ओर तर्क प्राप्त करें । मैं GetInterfacesअब साथ जाऊँगा : p
बेंजामिन

12
IsAssignableFrom(t1)संस्करण तेजी की अपेक्षा 3 गुना के बारे में है GetInterfaces().Contains(t2)मेरी कोड में समकक्ष।
पियरे अरनौद

24
@PierreArnaud: IsAssignableFrom अंततः GetInterfaces को कॉल करता है, इसलिए संभवतः आपके परीक्षण ने GetInterfaces को पहले और IsAssignable की जाँच की। ऐसा इसलिए है क्योंकि GetInterfaces के कैश में यह परिणाम है इसलिए पहला मंगलाचरण अधिक खर्च होता है
Panos Theof

17
@ कोस्टा के जवाब में एक छोटा सा बदलाव। C # 6 के साथ हम typeof(MyType).GetInterface(nameof(IMyInterface)) != nullबेहतर प्रकार की सुरक्षा और रीफैक्टरिंग कर सकते हैं ।
एओलम्स


32
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

या

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));

34
यदि आपके पास पहले से ही कक्षा का एक उदाहरण है तो बहुत ही बेहतर तरीका है someclass is IMyInterfaceक्योंकि इसमें प्रतिबिंब की लागत बिल्कुल भी शामिल नहीं है। तो, जबकि गलत नहीं है, यह करने के लिए एक आदर्श तरीका नहीं है।
जेम्स जे। रेगन IV

1
@ नाम - सहमत। यहां तक ​​कि Resharper भी यही सुझाव देता है।
अंशुमान अग्रवाल

@ JamesJ.ReganIV आपको एक उत्तर के रूप में पोस्ट करना चाहिए, मैंने आपकी टिप्पणी लगभग याद कर
ली है

@reggaeguitar, धन्यवाद, लेकिन टिप्पणी मूल प्रश्न का उत्तर नहीं देती है। प्रश्न परावर्तन समाधान के लिए पूछता है, मैं सिर्फ इस उत्तर के पहले मामले में कह रहा हूं जहां आपके पास वस्तु प्रतिबिंब का एक उदाहरण है आदर्श समाधान नहीं है।
जेम्स जे। रेगन IV

1
@ JamesJ.ReganIV दरअसल, isवंशानुक्रम पदानुक्रम के दोनों दिशाओं में IsAssignableFromजाँच करता है जबकि केवल ऊपर की ओर जाँच करता है। इसके अलावा, यदि आपके पास किसी वस्तु का उदाहरण है, तो आपको कॉल करना चाहिए IsInstanceOfType(जो केवल ऊपर की ओर दिखता है)।
3

13
public static bool ImplementsInterface(this Type type, Type ifaceType) 
{
    Type[] intf = type.GetInterfaces();
    for(int i = 0; i < intf.Length; i++) 
    {
        if(intf[ i ] == ifaceType) 
        {
            return true;
        }
    }
    return false;
}

मुझे लगता है कि यह तीन कारणों से सही रिलीज है:

  1. यह GetInterfaces का उपयोग करता है और IsAssignableFrom का उपयोग नहीं करता है, यह IsAssignableFrom के बाद से तेज़ी से होता है क्योंकि कई चेक GetInterfaces को कॉल करने के बाद।
  2. यह स्थानीय सरणी पर प्रसारित होता है, इसलिए कोई सीमा जाँच नहीं होगी।
  3. यह == ऑपरेटर का उपयोग करता है जिसे टाइप के लिए परिभाषित किया गया है, इसलिए संभवतः समान पद्धति (जो इसमें शामिल है कॉल, अंततः होगा) से अधिक सुरक्षित है।

10
सामग्री के लिए +1, मैं पारेंस और मिस्र के ब्रेसिज़ के आसपास की जगहों से नफरत करता हूं। साथ ही पूरी विधि के रूप में लिखा जा सकता है: रिटर्न टाइप.गेटइंटरफेस ()। कोई भी (टी => टी == ifaceType);
रेगिगुएटर

1
Type.IsAssignableFrom () आंतरिक रूप से आपके कोड की तरह कार्य करता है
devi

1
इसके अलावा क्यों नहीं टाइप करें। GetInterfaces ()। इसमें शामिल हैं (ifaceType) जो LINQ का उपयोग नहीं करता है।

9

मैंने अभी किया:

public static bool Implements<I>(this Type source) where I : class
{
  return typeof(I).IsAssignableFrom(source);
}

काश, मैं कह सकता where I : interface, लेकिन interfaceएक सामान्य पैरामीटर बाधा विकल्प नहीं है। classयह जितना करीब होता है।

उपयोग:

if(MyType.Implements<IInitializable>())
  MyCollection.Initialize();

मैंने सिर्फ Implementsइसलिए कहा क्योंकि यह अधिक सहज है। मैं हमेशा IsAssignableFromफ्लिप-फ्लॉप हो जाता हूं ।


आप return typeof(I).IsInterface && typeof(I).IsAssignableFrom(source);विधि के किसी भी 'गलत' उपयोग पर गलत वापसी कर सकते हैं , अर्थात्; इंटरफ़ेस प्रकार के बजाय एक वर्ग प्रकार के साथ इसका उपयोग करना, वैकल्पिक रूप से एक अपवाद को फेंक दें यदि टाइप-पैरामीटर इंटरफ़ेस नहीं है। यद्यपि आप तर्क दे सकते हैं कि एक व्युत्पन्न वर्ग 'लागू होता है' यह माता-पिता है ...
सिंदरी जोल्सन

7

इष्टतम प्रदर्शन के लिए जेफ के जवाब को संशोधित करना (पियरे अरनौद द्वारा प्रदर्शन परीक्षण के लिए धन्यवाद):

var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;

सभी प्रकार खोजने के लिए जो किसी दिए गए इंटरफ़ेस को लागू करते हैं Assembly:

var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
                          .Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);

7

जैसा कि किसी और ने पहले ही उल्लेख किया है: बेंजामिन अप्रैल 10 '13 22:21 "

यह सुनिश्चित करना आसान था कि ध्यान न दें और पीछे की ओर IsAssignableFrom के लिए तर्क प्राप्त करें। मैं अब GetInterfaces के साथ जाऊंगा: p -

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

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }
}

और क्यों नहीं थोड़ा और अधिक सामान्य हो (अच्छी तरह से यकीन है कि अगर यह सच है कि दिलचस्प नहीं है, अच्छी तरह से मुझे लगता है कि मैं बस 'वाक्यविन्यास' चीनी का एक और चुटकी पारित कर रहा हूँ):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }

    public static bool IsAssignableTo<TAssignable>(this Type type)
    {
        return IsAssignableTo(type, typeof(TAssignable));
    }
}

मुझे लगता है कि यह उस तरह से बहुत अधिक स्वाभाविक हो सकता है, लेकिन एक बार फिर बहुत व्यक्तिगत राय का मामला है:

var isTrue = michelleType.IsAssignableTo<IMaBelle>();

4
क्या कोई कारण है जो आपने कार्यान्वयन को सीधे विस्तार विधि में नहीं रखा है? मेरा मतलब है कि यह आपको इसे दोनों तरीकों से कॉल करने की अनुमति देता है, लेकिन आपको कभी ऐसा करने की आवश्यकता क्यों होगी?
मार्क ए। डोनोहे

@MarqueIV आपको लगभग 2 साल देर से वापस पाने के लिए खेद है, अच्छी तरह से मुझे लगता है कि यह एक पुरानी बुरी आदत थी, फिर कोड को दोहराने से बचने के लिए विस्तार विधि में सहायक विधि को लपेटने के लिए, मेरे उत्तर को संपादित करेगा :)
केरी पेरेट

1
@MarqueIV ने प्लस को उर्फ ​​का उपयोग न करने की मेरी दूसरी बुरी आदत को बदल दिया, अर्थात Boolean => bool(जब मैं छोटा था तब कोडिंग के कुछ सख्त "फैंसी" नियम नहीं थे)।
केरी पेरेट

3

यदि आपके पास एक प्रकार या उदाहरण है, तो आप आसानी से देख सकते हैं कि वे किसी विशिष्ट इंटरफ़ेस का समर्थन करते हैं या नहीं।

यह जांचने के लिए कि क्या कोई वस्तु एक निश्चित इंटरफ़ेस को लागू करती है:

if(myObject is IMyInterface) {
  // object myObject implements IMyInterface
}

यह जांचने के लिए कि क्या कोई प्रकार एक निश्चित इंटरफ़ेस लागू करता है:

if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
  // type MyType implements IMyInterface
}

यदि आपको एक सामान्य वस्तु मिली है और यदि आप जिस इंटरफ़ेस को डालते हैं वह कोड लागू होता है, तो एक कास्ट के साथ-साथ एक कास्ट करना चाहते हैं:

 var myCastedObject = myObject as IMyInterface;

    if(myCastedObject != null) {
      // object myObject implements IMyInterface
    }

2

IsAssignableFromअब इसे ले जाया गया है TypeInfo:

typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());

1

इसे खोजने वाला कोई भी व्यक्ति निम्नलिखित एक्सटेंशन विधि को उपयोगी पा सकता है:

public static class TypeExtensions
{
    public static bool ImplementsInterface(this Type type, Type @interface)
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        if (@interface == null)
        {
            throw new ArgumentNullException(nameof(@interface));
        }

        var interfaces = type.GetInterfaces();
        if (@interface.IsGenericTypeDefinition)
        {
            foreach (var item in interfaces)
            {
                if (item.IsConstructedGenericType && item.GetGenericTypeDefinition() == @interface)
                {
                    return true;
                }
            }
        }
        else
        {
            foreach (var item in interfaces)
            {
                if (item == @interface)
                {
                    return true;
                }
            }
        }

        return false;
    }
}

xunit परीक्षण:

public class TypeExtensionTests
{
    [Theory]
    [InlineData(typeof(string), typeof(IList<int>), false)]
    [InlineData(typeof(List<>), typeof(IList<int>), false)]
    [InlineData(typeof(List<>), typeof(IList<>), true)]
    [InlineData(typeof(List<int>), typeof(IList<>), true)]
    [InlineData(typeof(List<int>), typeof(IList<int>), true)]
    [InlineData(typeof(List<int>), typeof(IList<string>), false)]
    public void ValidateTypeImplementsInterface(Type type, Type @interface, bool expect)
    {
        var output = type.ImplementsInterface(@interface);
        Assert.Equal(expect, output);
    }
}

0

किस बारे में

if(MyType as IMyInterface != null)

?


4
यह स्पष्ट है जब मेरे पास एक उदाहरण है। उपयोगी नहीं है जब मेरे पास प्रतिबिंब से एक प्रकार है
edc65


0

एक सही उत्तर है

typeof(MyType).GetInterface(nameof(IMyInterface)) != null;

तथापि,

typeof(MyType).IsAssignableFrom(typeof(IMyInterface));

निम्न कोड और स्ट्रिंग के साथ शो के रूप में एक गलत परिणाम वापस आ सकता है:

    static void TestIConvertible()
    {
        string test = "test";
        Type stringType = typeof(string); // or test.GetType();

        bool isConvertibleDirect = test is IConvertible;
        bool isConvertibleTypeAssignable = stringType.IsAssignableFrom(typeof(IConvertible));
        bool isConvertibleHasInterface = stringType.GetInterface(nameof(IConvertible)) != null;

        Console.WriteLine($"isConvertibleDirect: {isConvertibleDirect}");
        Console.WriteLine($"isConvertibleTypeAssignable: {isConvertibleTypeAssignable}");
        Console.WriteLine($"isConvertibleHasInterface: {isConvertibleHasInterface}");
    }

परिणाम:

 isConvertibleDirect: True
 isConvertibleTypeAssignable: False
 isConvertibleHasInterface: True

4
जैसा कि आप स्वीकृत उत्तर में देख सकते हैं, आपने उपयोग के प्रकारों को आपस में जोड़ा है IsAssignableFrom। जैसे बेंजामिन और इहोर्न ने चेतावनी दी।
VV5198722

0

ध्यान दें कि यदि आपके पास एक सामान्य इंटरफ़ेस है IMyInterface<T>तो यह हमेशा वापस आएगा false:

  typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */

यह भी काम नहीं करता है:

  typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>))  /* ALWAYS FALSE */

हालाँकि, यदि यह MyTypeलागू होता है IMyInterface<MyType>और वापस आता है true:

  typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))

हालाँकि, आप संभावना Tरनटाइम पर प्रकार पैरामीटर पता नहीं होगा । कुछ हद तक घोल है:

  typeof(MyType).GetInterfaces()
                .Any(x=>x.Name == typeof(IMyInterface<>).Name)

जेफ़ का हल थोड़ा कम हैकी है:

  typeof(MyType).GetInterfaces()
         .Any(i => i.IsGenericType 
             && i.GetGenericTypeDefinition() == typeof(IMyInterface<>));

यहां Typeकिसी भी मामले के लिए काम करने की एक विस्तार विधि दी गई है:

public static class TypeExtensions
{
    public static bool IsImplementing(this Type type, Type someInterface)
    {
        return type.GetInterfaces()
             .Any(i => i == someInterface 
                 || i.IsGenericType 
                    && i.GetGenericTypeDefinition() == someInterface);
    }
}

(ध्यान दें कि उपरोक्त लाइनक का उपयोग करता है, जो संभवतः लूप की तुलना में धीमा है।)

आप तब कर सकते हैं:

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