Pergunta

Estou criando uma biblioteca reutilizável para o Silverlight.A biblioteca contém um tipo genérico interno e preciso criar uma nova instância desse tipo genérico, mas a certa altura não tenho um argumento de tipo genérico disponível, apenas um System.Type objeto que representa o argumento genérico.Tentei criar uma instância usando reflexão, mas falhou, porque essa classe é interna e o Silverlight funciona efetivamente com confiança parcial.

Aqui está o que tentei até agora:

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

Este é o meu tipo interno.Nada chique:

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

Eu até tentei abusar do Nullable<T> struct como uma fábrica para criar uma fábrica que possa produzir meu tipo interno.No entanto, padrão Nullable<T> seja convertido em referências nulas:

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

Como você pode imaginar, não quero tornar esse tipo público, pois poluiria minha API.Atualmente estou sem ideias.Quais são minhas opções?O que posso fazer para criar esse tipo interno?

Foi útil?

Solução

A terceira alternativa é suportar algum tipo de padrão de fábrica que conterá um método para instanciar o tipo interno.E você pode expor a fábrica ou tornar público o tipo de fábrica.

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

Você pode deixar a classe como interna e invocar o método TypeFactory por meio de reflexão.

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

Acho que seu TypeFactory deveria ser público, não pode ser interno.

Outras dicas

Você tem duas opções:

  1. Torne o tipo público
  2. Evite usar reflexão para fazer isso; em vez disso, use genéricos.

Se fosse possível evitar as salvaguardas só porque você não gosta delas, não haveria nenhuma necessidade de tê-las.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top