Hi,

I'm writing documentation generator for .NET Framework, I'm using
Mono.Cecil as a reflection engine, Mono.Cecil works perfectly except
one small detail. One of the task that documentation generator must be
able to do, is to generate syntax for various languages basing on the
reflection data. In order to generate syntax for generic type (class,
interface, delegate, structure), in addition to listing generic
parameters for a type, I also have to list generic arguments for base
type. The problem arises when I want filter generic arguments of base
class that doesn't belong directly to base class, but they belong to
enclosing class of base class. Consider the following code:

// test.dll
using System;
namespace Application
{
    public class EnclosingClass<A>
    {
        public class NestedClass<B> : EnclosingClass<A>
        {
            public class SecondNestedClass<C, D> : NestedClass<B>
            {
                //
            }
        }
    }
}

Let's suppose that I want to generate syntax for SecondNestedClass<C,
D>, but this type is nested inside other generic types, so I have to
use GenericParameter.Owner property to filter generic paramters that
doesn't belong to SecondNestedClass class and ommit them in generic
parameter listing (A, B). So far so good, but when I want to list
generic arguments for base class of SecondNestedClass this approach
doesn't work ! The GenericParameter.Owner property for NestedClass<B>
always returns SecondNestedClass<C, D>. To make it more clear, I wrote
the following code:

using System;

using Mono.Cecil;

namespace App
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Change this path !!!
            AssemblyDefinition assemblyDef =
AssemblyFactory.GetAssembly("C:\\test.dll");

            foreach (ModuleDefinition tempModuleDef in
assemblyDef.Modules)
            {
                foreach (TypeDefinition tempTypeDef in
tempModuleDef.Types)
                {
                    // try find SecondNestedClass<B, C>
                    if(tempTypeDef.Name == "SecondNestedClass`2")
                    {
                        // show class name
                        Console.WriteLine();
                        Console.WriteLine("Class name:
SecondNestedClass ");

                        // show base class name
                        Console.WriteLine("Base class: " +
tempTypeDef.BaseType.Name);

                        // list generic arguments of base class
                        GenericInstanceType baseGenericType =
tempTypeDef.BaseType as GenericInstanceType;
                        foreach (TypeReference tempGenricArg in
baseGenericType.GenericArguments)
                        {
                            // convert to generic parameter
                            GenericParameter genericParam =
tempGenricArg as GenericParameter;

                            // show generic parameter and its owner
                            Console.WriteLine("Parameter name: " +
genericParam.Name +
                                ", owner: " + (genericParam.Owner as
TypeReference).Name);
                        }
                    }
                }
            }

            Console.ReadKey();
        }
    }
}

This program produces the following output:

Class name: SecondNestedClass
Base class: NestedClass`1
Parameter name: A, owner: SecondNestedClass`2
Parameter name: B, owner: SecondNestedClass`2

I thought that "owner" should be EnclosingClass`1 and NestedClass`1
respectively, is this behavior correct ?

Thanks in advance.
-- 
--
mono-cecil

Reply via email to