Я создаю многоразовую библиотеку для 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>
как фабрикой для создания фабрики, которая могла бы производить мой внутренний тип. Однако по умолчанию 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. У меня сейчас нет идей. Какие у меня варианты? Что я могу сделать, чтобы создать этот внутренний тип?
2 ответа
Третья альтернатива - поддержка некоего фабричного шаблона, который будет содержать метод для создания экземпляра внутреннего типа. И вы можете выставить factory или сделать общедоступным тип factory.
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 должен быть публичным, он не может быть внутренним.
У вас есть два варианта:
- Сделайте тип общедоступным
- Избегайте использования отражения для этого, используйте вместо этого универсальные шаблоны.
Если бы защитных мер можно было избежать только потому, что они вам не нравились, в них вообще не было бы необходимости.
Похожие вопросы
Новые вопросы
c#
C# (произносится как «see Sharp») — это высокоуровневый мультипарадигменный язык программирования со статической типизацией, разработанный Microsoft. Код C# обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, которое включает в себя .NET, .NET Framework, .NET MAUI и Xamarin среди прочих. Используйте этот тег для ответов на вопросы о коде, написанном на C#, или о формальной спецификации C#.
T
, толькоSystem.Type
, представляющий этотT
.