2010-10-27 10 views
2

Pour créer des délégués à la volée, les techniques varient de Delegate.CreateDelegate à Expresion Lambda, DynamicMethod, etc. Toutes ces techniques exigent que vous sachiez le tapez du délégué. J'essaie de convertir les délégués fermés en délégués ouverts génériquement, et pour ce faire, il semble que je dois créer dynamiquement le type de délégué ouvert avant de pouvoir créer le délégué qui en résulte. Considérez:Comment définir un type de délégué lors de l'exécution (type délégué dynamique)

pubic class WeakEvent<TDelegate> where TDelegate : class 
{ 
    public WeakEvent(Delegate aDelegate) 
    { 
     var dgt = aDelegate as TDelegate; 

     if(dgt == null) 
      throw new ArgumentException("aDelegate"); 

     MethodInfo method = dgt.Method; 
     var parameters = Enumerable 
         .Repeat(dgt.Target.GetType(),1) 
         .Concat(method.GetParameters().Select(p => p.ParameterType)); 

     Type openDelegateType = // ??? original delegate, with new 1st arg for @this 

     var dm = new DynamicMethod("InnerCode", method.ReturnType, parameters); 

     ... your favourite IL code emmisions go here 

     var openDelegate = dm.CreateDelegate(openDelegateType); 
    } 
} 

Le purpsoe du code ci-dessus est de créer un nouveau délégué qui est identique au délégué d'origine, mais a un nouveau 1er argument en faveur de cette ... soit une version ouverte de la fermeture précédemment déléguer.

Existe-t-il un moyen simple de cloner & modifier un type de délégué existant, ou est la solution la plus proche pour construire les types génériques Func <> et Action <>?

Répondre

0

@ Mark - Après votre 2ème exemple de code, vous avez dit:

C'est dommage, parce que cela signifie (comme autant que je peux dire), que vous ne pouvez pas dynamiquement [re] créer des délégués avec ref ou out arguments, puisque les génériques Func et Action ne permettra pas il.

C'était exactement mon problème, voir Create C# delegate type with ref parameter at runtime pour la solution de l'utilisateur Ani: Expression.GetDelegateType permet paramètres ref.

1

Le nouveau délégué avec une signature différente est un nouveau type. C# étant de type sécurisé, il n'est pas possible de le faire - autre que de baratter du code et de compiler à l'exécution ce qui, en dehors de la fuite de mémoire, n'est pas une approche si élégante.

Mais ce que vous pouvez faire est de choisir un délégué approprié dans la liste des actions déjà faites <> ou Func <> en fonction du type de délégué. Vous pouvez également créer vos propres lits, en fonction de vos types attendus, et choisir cela en cours d'exécution.

1

Après un peu experiemntation, j'ai trouvé que le code suivant est la meilleure façon d'obtenir ce que j'espérais:

private Type CreateOpenDelegate() 
    { 
     var parms = _method.GetParameters(); 
     bool hasReturn = _method.ReturnType != typeof (void); 
     Type generic = GetGenericTypeForOpenDelegate(parms, hasReturn); 

     var argTypes = new List<Type>(parms.Length + 2) {_method.DeclaringType}; 

     foreach (var arg in parms) 
     { 
      if(arg.IsOut || arg.IsRetval) 
       throw new NotImplementedException(); 

      argTypes.Add(arg.ParameterType); 
     } 

     if(hasReturn) 
      argTypes.Add(_method.ReturnType); 

     var result = generic.MakeGenericType(argTypes.ToArray()); 

     return result; 
    } 

    private static Type GetGenericTypeForOpenDelegate(ParameterInfo[] parms, bool hasReturn) 
    { 
     if (hasReturn) 
     { 
      switch (parms.Length) 
      { 
       case 0: 
        return typeof (Func<,>); 
        break; 
       case 1: 
        return typeof (Func<,,>); 
        break; 
       case 2: 
        return typeof (Func<,,,>); 
        break; 
       case 3: 
        return typeof (Func<,,,,>); 
        break; 
      } 
     } 
     else 
     { 
      switch (parms.Length) 
      { 
       case 0: 
        return typeof (Action<>); 
        break; 
       case 1: 
        return typeof (Action<,>); 
        break; 
       case 2: 
        return typeof (Action<,,>); 
        break; 
       case 3: 
        return typeof (Action<,,,>); 
        break; 
      } 
     } 
     throw new NotImplementedException(); 
    } 

C'est dommage, parce que cela signifie (pour autant que je peut dire), que vous ne pouvez pas dynamiquement [re] créer des délégués avec ref ou sur arguments, puisque les génériques Func et Action ne le permettront pas.

Questions connexes