Trust parziale: come istanziare un tipo generico senza un argomento tipo generico
-
14-11-2019 - |
Domanda
Sto creando una biblioteca riutilizzabile per Silverlight.La biblioteca contiene un tipo generico interno e ho bisogno di creare una nuova istanza di questo tipo generico, ma a un punto non ho un argomento tipo generico disponibile, solo un oggetto System.Type
che rappresenta l'argomento generico.Ho provato a creare un'istanza usando la riflessione, ma questo fallisce, perché questa classe è interna e Silverlight esegue efficacemente in trust parziale.
Ecco cosa ho provato finora:
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;
}
.
Questo è il mio tipo interno.Niente di fantasia:
internal class InternalGenericType<T> : INonGenericInterface
where T : class
{
public InternalGenericType()
{
}
}
.
Ho persino provato abusare della struttura Nullable<T>
come fabbrica per creare una fabbrica che potrebbe produrre il mio tipo interno.Tuttavia, Nullable<T>
predefinito viene convertito in riferimenti NULL:
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>();
}
}
}
.
Come puoi immaginare, non voglio rendere questo tipo pubblico, perché inquinerebbe la mia API.Sono attualmente senza idee.Quali sono le mie opzioni?Cosa posso fare per creare questo tipo interno?
Soluzione
La terza alternativa è supportare una sorta di modello di fabbrica che conterrà un metodo per installare il tipo interno.E puoi esporre la fabbrica o rendere pubblico il tipo di fabbrica.
public class TypeFactory
{
public static object Create<T>()
{
return new MyInternalType<T>();
}
}
.
È possibile lasciare la classe come interna e puoi richiamare il metodo di tipografo tramite la riflessione.
public object CreateType(System.Type type)
{
Type typeFactory = typeof(TypeFactory);
MethodInfo m = typeFactory.GetMethod("Create").MakeGenericMethod(type);
return m.Invoke(null, null);
}
.
Penso che il tuo tipo di tipici debba essere pubblico, non può essere interno.
Altri suggerimenti
Hai due scelte:
- .
- Rendi il tipo pubblico
- Evita di usare la riflessione per farlo, usa invece i generici.
Se le salvaguardie fossero possibili per evitare solo perché non ti piacciono, non ci sarebbe bisogno di averli affatto.