2013-07-24 4 views
0

Je cherche un moyen plus rapide que Activator.CreateInstance d'instancier une classe de son type.Instancier une classe avec son type

Je le fais de cette façon pour l'instant: Activator.CreateInstance(typeof(LoginView)); mais c'est extrêmement lent: je vois des retards lors de l'instanciation des différentes vues.

Une suggestion pour moi? Je googler pendant des heures maintenant et je ne l'ai pas trouver un moyen plus rapide que cela pour faire ce que je veux ..:/

Merci beaucoup (:

+2

'new LoginView()' devrait fonctionner. Ou est-ce que je manque quelque chose? –

+1

En cache un délégué compilé qui appelle le ctor. – SLaks

+1

Je suppose que 'typeof (LoginView)' n'est pas l'argument réel, ou bien vous auriez pu écrire 'new LoginView()', comme le suggère Cédric. Mais dans tous les cas, êtes-vous sûr que lag vient de la couche de réflexion et non du constructeur 'LoginView' lui-même? –

Répondre

1

Vous pouvez utiliser des génériques.

T MyActivator<T>() where T : new() { return new T(); } 

T MyActivator<T>(T variable) where T : new() { return new T(); } 

La première est utilisée si vous connaissez le type (utilisez explicitement le type).
Le second est utilisé pour déduire le type d'une variable:

MyType blah = MyActivator<MyType>(); 

SomeType someVar; 
object blah = MyActivator(someVar); 
+0

S'il reçoit un Type contenant le résultat de typeof, comme il dit dans son commentaire, cela ne marchera pas. – fcuesta

+0

-1, 'new T()' est juste encore une réflexion (pour le type de référence). Voir http://stackoverflow.com/questions/6708459/given-where-t-new-does-new-t-use-activator-createinstance-internally. Vous devez aller la route d'expression, voir ceci: http://stackoverflow.com/q/6582259/661933 – nawfal

1

EDIT Il semble que le type est . générique, et non pas seulement LoginView Vous pouvez essayer ceci:.

public void Foo<T>(T input) where T : new() 
{ 
    var myInstance = new T(); 
} 
+0

Encore, 'nouveau T()' n'améliore pas les performances .. – nawfal

4

Vous pouvez utiliser des expressions Linq comme expliqué dans ce blog post dans votre cas, il serait

ConstructorInfo ctor = typeof(LoginView).GetConstructors().First(); 
ObjectActivator<LoginView> createdActivator = GetActivator<LoginView>(ctor); 


LoginView instance = createdActivator(); 

Au cas où le lien va vers le bas, c'est ObjectActivator délégué

delegate T ObjectActivator<T>(params object[] args); 

et la méthode GetActivator

public static ObjectActivator<T> GetActivator<T> 
    (ConstructorInfo ctor) 
{ 
    Type type = ctor.DeclaringType; 
    ParameterInfo[] paramsInfo = ctor.GetParameters();     

    //create a single param of type object[] 
    ParameterExpression param = 
     Expression.Parameter(typeof(object[]), "args"); 

    Expression[] argsExp = 
     new Expression[paramsInfo.Length];    

    //pick each arg from the params array 
    //and create a typed expression of them 
    for (int i = 0; i < paramsInfo.Length; i++) 
    { 
     Expression index = Expression.Constant(i); 
     Type paramType = paramsInfo[i].ParameterType;    

     Expression paramAccessorExp = 
      Expression.ArrayIndex(param, index);    

     Expression paramCastExp = 
      Expression.Convert (paramAccessorExp, paramType);    

     argsExp[i] = paramCastExp; 
    }     

    //make a NewExpression that calls the 
    //ctor with the args we just created 
    NewExpression newExp = Expression.New(ctor,argsExp);     

    //create a lambda with the New 
    //Expression as body and our param object[] as arg 
    LambdaExpression lambda = 
     Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);    

    //compile it 
    ObjectActivator<T> compiled = (ObjectActivator<T>)lambda.Compile(); 
    return compiled; 
} 

Un avantage à utiliser cette méthode sur la méthode générique est que vous pouvez facilement passer dans les paramètres à votre constructeur mais le désavantage étant le code plus verbeux.

+0

C'est un cool, mais je n'ai pas besoin pour passer des paramètres, donc je vais garder le code de Yohai qui est moins verbeux: P Merci quand même :) – dotixx

+0

@dotixx - Pas de problème, utilisez ce qu'il y a de mieux pour vous :) – keyboardP

1

Au lieu de prendre un Type qui renvoie le résultat de typeof, prendre un délégué qui vous obtient une instance de l'objet:

Func<object> myActivator =() => new LoginView(); 

Peut-être même avoir une méthode pour vous aider à le faire, si elle avait le rendre plus facile sur votre code:

public static Func<object> GetActivator<T>() where T : new() 
{ 
    return() => new T(); 
} 

Cela aura une très petite surcharge pour appeler le délégué Func. Devrait être beaucoup plus rapide que d'appeler Activator.CreateInstance sur un Type.

Questions connexes