Question

Je crée une bibliothèque réutilisable pour Silverlight. La bibliothèque contient un type générique interne et j'ai besoin de créer une nouvelle instance de ce type générique, mais à un moment donné, je n'ai pas d'argument de type générique disponible, seulement un System.Type objet qui représente l'argument générique. J'ai essayé de créer une instance en utilisant la réflexion, mais cela échoue, car cette classe est interne et Silverlight s'exécute efficacement en fiducie partielle.

Voici ce que j'ai essayé jusqu'à présent:

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;
}

Ceci est mon type interne. Rien d'extraordinaire:

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

J'ai même essayé de maltraiter le Nullable<T> Struct comme une usine pour créer une usine qui pourrait produire mon type interne. Cependant, par défaut Nullable<T> Soyez converti en références nuls:

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>();
       }
   }
}

Comme vous pouvez l'imaginer, je ne veux pas rendre ce type public, car cela polluerait mon API. Je suis actuellement à court d'idées. Quelles sont mes options? Que puis-je faire pour créer ce type interne?

Était-ce utile?

La solution

La troisième alternative consiste à prendre en charge une sorte de modèle d'usine qui contiendra une méthode pour instancer le type interne. Et vous pouvez exposer l'usine ou rendre le type d'usine public.

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

Vous pouvez laisser la classe comme interne et vous pouvez invoquer la méthode de TypeFactory via la réflexion.

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

Je pense que votre type de type devrait être public, il ne peut pas être interne.

Autres conseils

Vous avez deux choix:

  1. Rendre le type public
  2. Évitez d'utiliser la réflexion pour ce faire, utilisez plutôt des génériques.

Si les garanties étaient possibles pour éviter simplement parce que vous ne les aimiez pas, il ne serait pas nécessaire de les avoir du tout.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top