简体   繁体   中英

C# Reflection: How to determine if ParameterInfo is a generic type defined on parent class

I have a method signature like this:

public class Class1<TItem>
{
    public void CopyTo(TItem[] items) { }
}

where TItem is declared on the parent class.

When I use Reflection to parse this method:

// not returning TItem as generic in signature    
string sig = method.FullName; // ClassLibrary1.Class1`1.CopyTo(TItem[])

if (method.ContainsGenericParameters) // true
{
           Type[] genericArgs = method.GetGenericArguments(); // returns empty
           foreach (Type genericArg in genericArgs)
           {
               loM.cGenericParameters += genericArg.Name + ",";
           }
 }

I need to figure out what the generic type signature is so I can look at the XML documentation (need to build the funky generic type lookup signature). I need to map the method signature to what's in the XML documentation which looks like this:

<member name="M:ClassLibrary1.Class1`1.CopyTo(`0[])">

I'm unable to reliably detect whether TItem[] is generic and figure out how to get the generic index (generically).

When I look at the parameter signature, the ParameterType.IsGenericType is false as is .GenericParameterPosition . ParameterType.ContainsGenericParameters is true, but nowhere does it give me the generic raw type signature (ie. '0[] that the signature requires and is usually seen in the .FullName property).

This all works if the Generic definition is on actual method (ie. SomeMethod<TItem>(TItem[] blah) at which point I can parse out the parameters as I need to. But when the generic parameter is defined on the type I can't figure out the right signature to reference the parent generic type by it's generic parameter position.

I think the problem is that you're looking at the generic arguments of the method instead of the method's parameters. You'll also have to differentiate between an array and a generic type.

if (method.ContainsGenericParameters)
{
    foreach (var parameter in method.GetParameters())
    {
        if (parameter.ParameterType.IsArray)
        {
            var elementType = parameter.ParameterType.GetElementType();

            var genericArgName = elementType.Name;
            var genericParameterPosition = elementType.GenericParameterPosition;
        }
        else if (parameter.ParameterType.IsGenericType)
        {
            foreach (var genericArg in parameter.ParameterType.GetGenericArguments())
            {
                var genericArgName = genericArg.Name;
                var genericParameterPosition = genericArg.GenericParameterPosition;

                // If you need to differentiate between a generic arg that is declared
                // in the method versus being declared in the class/interface/struct:
                if (genericArg.DeclaringMethod == null)
                {
                    // Declared in the class/interface/struct
                }
                else
                {
                    // Declared in the method
                }
            }
        }
    }
}

Things get a little weird when you have something like Class2<>.Foo<> below - the genericArg variable will have a GenericParameterPosition of 0 for both iterations of the foreach loop. Check the DeclaringMethod property for a null value to determine what that position refers to: the method or the class/interface/struct.

public class Class2<TKey>
{
    public void Foo<TValue>(IDictionary<TKey, TItem> items) { }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM