0

I'm trying to create an instance of a type with a generic where the type passed as a generic also has a generic.

The following code is where the problem occurs:

internal virtual RouteBase GetRoute(DbContextTypeProvider databaseContextTypeProvider, Type model)
{
    Type catchallRoute = typeof(CatchallRoute<,>);
    catchallRoute.MakeGenericType(new Type[] {
        databaseContextTypeProvider.DbContextType,
        model
    });

    Type routeTypeWrapper = typeof(RouteTypeWrapper<>);
    routeTypeWrapper.MakeGenericType(new Type[] {
        catchallRoute
    });

    RouteTypeProvider routeTypeProvider = (RouteTypeProvider)Activator.CreateInstance(routeTypeWrapper);

    return GetRoute(databaseContextTypeProvider, model, routeTypeProvider);
}

I based the code around what can be seen in the following SO question, when I use one type requiring generics in the same way as shown in the accepted answer the instance can be created, but the type requires a type with generics I just can't seem to get this working:

Pass An Instantiated System.Type as a Type Parameter for a Generic Class

I can't find any examples on MSDN showing how to create an instance of a type with generics where one of the generics it requires also requires generics.

If I code it so that the types are closed it would look like the following:

RouteTypeWrapper<CatchallRoute<SapphireDbContext<SiteTree>,SiteTree>> routeTypeProvider = new RouteTypeWrapper<CatchallRoute<SapphireDbContext<SiteTree>,SiteTree>>();

This is effectively what I'm trying to do but using reflection so that arguments can be passed to a method so that an instance can be created and returned.

But when I use reflection I get the following error:

Cannot create an instance of Sapphire.Cms.Web.Routing.RouteTypeWrapper`1[TRoute] because Type.ContainsGenericParameters is true.

Is what I'm trying to do possible and if so how can I correct the code so that it works?

Community
  • 1
  • 1
Professor of programming
  • 2,978
  • 3
  • 30
  • 48

2 Answers2

1

MakeGenericType returns a new type. It does not modify the existing type. Change your code as below to get the result of MakeGenericType

internal virtual RouteBase GetRoute(DbContextTypeProvider databaseContextTypeProvider, Type model)
{
    Type catchallRoute = typeof(CatchallRoute<,>).MakeGenericType(new Type[] {
        databaseContextTypeProvider.DbContextType,
        model
    });

    Type routeTypeWrapper = typeof(RouteTypeWrapper<>).MakeGenericType(new Type[] {
        catchallRoute
    });

    RouteTypeProvider routeTypeProvider = (RouteTypeProvider)Activator.CreateInstance(routeTypeWrapper);

    return GetRoute(databaseContextTypeProvider, model, routeTypeProvider);
}
Grax32
  • 3,986
  • 1
  • 17
  • 32
  • 1
    `typeof(RouteTypeWrapper<>)` returns the open generic type. `RouteTypeWrapper<>`. MakeGenericType returns the closed generic type `RouteTypeWrapper,SiteTree>>`. The problem in your code was that the result of MakeGenericType was being discarded instead of being put into the variable routeTypeWrapper – Grax32 Apr 02 '15 at 16:08
1

Here is simple example showing how to do that.

class A<T>{}
class B<T>{}
class C<T>{}

...

var atype = typeof(A<>).MakeGenericType(new [] { typeof(int) });
var btype = typeof(B<>).MakeGenericType(new [] { atype });
var ctype = typeof(C<>).MakeGenericType(new [] { btype });

var cinstance = Activator.CreateInstance(ctype);
Michał Komorowski
  • 6,198
  • 1
  • 20
  • 24