Частичное доверие:Как создать экземпляр универсального типа без аргумента универсального типа

StackOverflow https://stackoverflow.com/questions/5477179

Вопрос

Я создаю многоразовую библиотеку для Silverlight.Библиотека содержит внутренний универсальный тип, и мне нужно создать новый экземпляр этого универсального типа, но в какой-то момент у меня нет доступного аргумента универсального типа, есть только System.Type объект, представляющий общий аргумент.Я попытался создать экземпляр с помощью отражения, но это не удалось, поскольку этот класс является внутренним, а Silverlight эффективно работает с частичным доверием.

Вот что я пробовал до сих пор:

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

Это мой внутренний тип.Ничего особенного:

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

Я даже пытался злоупотребить Nullable<T> struct как фабрика для создания фабрики, которая могла бы производить мой внутренний тип.Однако по умолчанию Nullable<T> преобразоваться в нулевые ссылки:

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

Как вы понимаете, я не хочу делать этот тип общедоступным, потому что это загрязнит мой API.На данный момент у меня нет идей.Какие у меня есть варианты?Что я могу сделать, чтобы создать этот внутренний тип?

Это было полезно?

Решение

Третья альтернатива — поддержка своего рода фабричного шаблона, который будет содержать метод для создания экземпляра внутреннего типа.И вы можете раскрыть фабрику или сделать тип фабрики общедоступным.

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

Вы можете оставить класс внутренним и вызывать метод TypeFactory через отражение.

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

Я думаю, что ваша TypeFactory должна быть общедоступной, она не может быть внутренней.

Другие советы

У вас есть два варианта:

  1. Сделать тип общедоступным
  2. Избегайте использования отражения для этого, вместо этого используйте дженерики.

Если бы средств защиты можно было избежать только потому, что они вам не нравятся, в них вообще не было бы необходимости.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top