2

I'm creating a reusable library for Silverlight. The library contains an internal generic type and I need to create a new instance of this generic type, but I at one point I don't have a generic type argument available, only a System.Type object that represents the generic argument. I tried to create an instance using reflection, but this fails, because this class is internal and Silverlight effectively runs in partial trust.

Here is what I tried so far:

private INonGenericInterface CreateInstance(Type type)
{
    // Activator.CreateInstance fails
    var instance = Activator.CreateInstance(
            typeof(InternalGenericType<>).MakeGenericType(type));

    // Invoking the default constructor of that type fails.
    var producer = typeof(InternalGenericType<>)
        .MakeGenericType(type)
        .GetConstructor(new Type[0])
        .Invoke(null);

    return (INonGenericInterface)producer;
}

This is my internal type. Nothing fancy:

internal class InternalGenericType<T> : INonGenericInterface
    where T : class
{
    public InternalGenericType()
    {
    }
}

I even tried abusing the Nullable<T> struct as a factory for creating a factory that could produce my internal type. However, default Nullable<T> get converted to null references:

internal static class InternalGenericTypeFactory
{
   public static INonGenericInterface Create(Type serviceType)
   {
      var nullType = typeof(Nullable<>).MakeGenericType(
         typeof(Factory<>).MakeGenericType(serviceType));

      // Activator succesfully creates the instance, but .NET
      // automatically converts default Nullable<T>s to null.
      object nullInstance = Activator.CreateInstance(nullType);

      var getValueMethod =
         nullType.GetMethod("GetValueOrDefault", new Type[0]);

      // Invoke fails, because nullInstance is a null ref.
      var factory = getValueMethod.Invoke(nullInstance, null);

      return ((IFactory)factory).CreateInstance();
   }

   internal interface IFactory
   {
      INonGenericInterface CreateInstance();
   }

   internal struct Factory<T> : IFactory where T : class
   {
       public INonGenericInterface CreateInstance()
       {
           return new InternalGenericType<T>();
       }
   }
}

As you can imagine, I don't want to make this type public, because it would pollute my API. I'm currently out of ideas. What are my options? What can I do to create this internal type?

Steven
  • 166,672
  • 24
  • 332
  • 435

2 Answers2

4

Third alternative is to support some sort of factory pattern which will contain a method to instanciate internal type. And you can expose factory or make factory type public.

public class TypeFactory
{
    public static object Create<T>()
    {
         return new MyInternalType<T>();
    }
}

You can leave class as internal and you can invoke TypeFactory's method via reflection.

public object CreateType(System.Type type)
{
    Type typeFactory = typeof(TypeFactory);
    MethodInfo m = typeFactory.GetMethod("Create").MakeGenericMethod(type);
    return m.Invoke(null, null);
}

I think your TypeFactory should be public, it can not be internal.

Steven
  • 166,672
  • 24
  • 332
  • 435
Akash Kava
  • 39,066
  • 20
  • 121
  • 167
  • I'm not sure I follow you. Can you give an example? – Steven Mar 29 '11 at 18:51
  • @Akash: Thanks for the example, but this will unfortunately not do the trick, because I don't have a generic `T`, just a `System.Type` representing that `T`. – Steven Mar 29 '11 at 19:38
  • Where does the T come from? Can't you supply a factory delegate or something instead/alongside it? – Lasse V. Karlsen Mar 29 '11 at 19:56
  • @Lasse: Is this a question for @Akash or for me? If it's for me; I'm not sure I follow you. Can you elaborate? – Steven Mar 30 '11 at 06:24
  • @Steven, you will have to use reflection to call this method, I have shown you the example. – Akash Kava Mar 30 '11 at 07:51
  • @Akash: Haha.. now I see. That's a smart one (+ for that). I still don't like making such factory public, but it is better than making the internal type public. – Steven Mar 30 '11 at 08:00
  • @Akash: Perhaps I can even 'abuse' some already existing parts of the API to do this. This way I don't have to pollute my API. I'm going to meditate on this :-). – Steven Mar 30 '11 at 08:05
  • @Steven, yes, if you look at .NET's BCL, most of time they implement IServiceProvider and they provide service to expose internal types with help of publicly implemented interfaces. – Akash Kava Mar 30 '11 at 08:08
3

You have two choices:

  1. Make the type public
  2. Avoid using reflection to do this, use generics instead.

If the safeguards were possible to avoid just because you didn't like them, there wouldn't be a need to have them at all.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • Thanks for your response. I'm not trying to avoid the Silverlight security mechanism, don't worry :-). I was afraid that these were my options. – Steven Mar 29 '11 at 18:36
  • Apologies if it sounded like I implied you were, but yes, those are your choices, due to the security system in Silverlight. I'm assuming creating an out-of-browser application in Silverlight that runs with full trust is not an option? – Lasse V. Karlsen Mar 29 '11 at 18:38
  • Running in full trust is not an option. It is a reusable library, and restricting my users to run it in full trust is simply a restriction that is too big. – Steven Mar 29 '11 at 18:41