views:

107

answers:

5

Hi all,

I have a MethodInfo passed in to a function and I want to do the following

MethodInfo containsMethod = typeof(ICollection<>).GetMethod("Contains");
if (methodInfo.Equals(containsMethod)
{
   // do something
}

But this doesn't work because the methodInfo has a specific generic type. For the example does work if I knew that the ICollection was always of type string.

MethodInfo containsMethod = typeof(ICollection<string>).GetMethod("Contains");
if (methodInfo.Equals(containsMethod)
{
   // do something
}

How can I check whether the MethodInfo is a ANY typed instance of the generic method without caring what the type is?

Thanks.

EDIT: Question clarification

As correctly pointed out the method is not generic but the containing class is so the question is more how to I find out if the MethodInfo is for a Type which is a typed instance of ICollection<>.

EDIT: more context

I am writing a Linq provider and trying to handle the "in" case

IList<string> myList = new List<string>{ "1", "2" };

from Something s in ...
where myList.Contains(s.name)
select s;
+4  A: 

Note that ICollection<T>.Contains is not a generic method - it is a non-generic method of a generic type. Otherwise IsGenericMethod and GetGenericTypeDefinition would help. You could obtain the generic type definition (DeclaringType.GetGenericTypeDefinition()) and work back up to Contains, but I wonder if you are approaching this problem the hard way.

Usually, if you are using reflection, it may be pragmatic to drop to non-generic IList - unless you need the type data (for example, for meta-programming). And in that case, I would consider looking closely to see if you can simplify the setup here.

Marc Gravell
Thanks for the reply. Added some context above for what I am trying to achieve. The DeclaringType approach looks promising, I will try it and get back.
Mike Q
A: 

The problem is that you don't have a generic method: you have a non-generic method on a generic type. I don't know of a way to use reflection to go directly from a method definition on an open generic type to that same method on a closed generic type or vice versa. However, you can take advantage of the fact that the methods returned by GetMethods() on the open and closed generic types should always be in the same order and do the translation by index:

MethodInfo containsMethod = typeof(ICollection<>).GetMethod("Contains");
var methodIndex = Array.IndexOf(methodInfo.DeclaringType.GetMethods(), methodInfo);
var methodOnTypeDefinition = methodInfo.DeclaringType.GetGenericTypeDefinition().GetMethods()[methodIndex];
if (methodOnTypeDefinition.Equals(containsMethod))
{
    // do something
}
Quartermeister
+3  A: 

You could check the declaring type:

if( methodInfo.Name == "Contains" 
    &&  methodInfo.DeclaringType.IsGenericType
    && methodInfo.DeclaringType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
Andrew Kennan
Simplest and clearest IMO, thanks.
Mike Q
+2  A: 

Some error checking would need to be added to this, but I believe this roughly does what you want. You can use a method with or without a type argument as the parameter.

static bool IsContainsMethod(MethodInfo methodInfo)
{
    Type[] types = { methodInfo.GetParameters().First().ParameterType };
    MethodInfo containsMethod = typeof(ICollection<>).MakeGenericType(types).GetMethod("Contains");
    return methodInfo.Equals(containsMethod);
}
Anthony Pegram
A: 

try this method

    public static bool CheckGenericMethod(MethodInfo methodInfo)
    {
        bool areSimilarMethods = false;
        MethodInfo methodToCompare = typeof(ISomeInterface<>).GetMethod("func");
        Type interfaceInfo = methodInfo.DeclaringType.GetInterface(methodToCompare.DeclaringType.FullName);

        if (interfaceInfo != null)
            areSimilarMethods = (methodToCompare.Name.Equals(methodInfo.Name)
            && interfaceInfo.FullName.Contains(methodToCompare.DeclaringType.FullName));
        else
        {
            areSimilarMethods = methodToCompare.DeclaringType.Equals(methodInfo.DeclaringType);
        }

        return areSimilarMethods;

    }

and here is the full example usage.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace TestReflection
{
    public class Program
    {
        static void Main(string[] args)
        {
            MethodInfo info1 = typeof(ISomeInterface<>).GetMethod("func");
            MethodInfo info2 = typeof(MyStringCollection).GetMethod("func");
            MethodInfo info3 = typeof(MyProgramCollection).GetMethod("func");
            MethodInfo info4 = typeof(MyXCollection).GetMethod("func");

            if (CheckGenericMethod(info1)) Console.WriteLine("true");else Console.WriteLine("false");
            if (CheckGenericMethod(info2)) Console.WriteLine("true");else Console.WriteLine("false");
            if (CheckGenericMethod(info3)) Console.WriteLine("true");else Console.WriteLine("false");
            if (CheckGenericMethod(info4)) Console.WriteLine("true"); else Console.WriteLine("false");

            Console.ReadKey();
        }


        public static bool CheckGenericMethod(MethodInfo methodInfo)
        {
            bool areSimilarMethods = false;
            MethodInfo methodToCompare = typeof(ISomeInterface<>).GetMethod("func");
            Type interfaceInfo = methodInfo.DeclaringType.GetInterface(methodToCompare.DeclaringType.FullName);

            if (interfaceInfo != null)
                areSimilarMethods = (methodToCompare.Name.Equals(methodInfo.Name)
                && interfaceInfo.FullName.Contains(methodToCompare.DeclaringType.FullName));
            else
            {
                areSimilarMethods = methodToCompare.DeclaringType.Equals(methodInfo.DeclaringType);
            }

            return areSimilarMethods;

        }
    }

    public interface ISomeInterface<T> where T : class
    {
        T func(T s);
    }

    public class MyStringCollection : ISomeInterface<string>
    {
        public string func(string s)
        {
            return s;
        }
    }

    public class MyProgramCollection : ISomeInterface<Program>
    {
        public Program func(Program s)
        {
            return s;
        }
    }

    public class MyXCollection
    {
        public int func(int s)
        {
            return s;
        }
    }

}
Tiju John