2010-11-24 8 views
2

Je souhaite calculer la métrique TCC:Comment trouver des paires en double dans un dictionnaire?

La cohésion Tight Classe (TCC) Mesures le rapport entre le nombre de paires de méthode de méthodes visibles directement connectés dans une classe NDC (C) et le nombre de méthodes possibles maximales paires de connexions entre les méthodes visibles d'une classe NP (C). Deux méthodes visibles sont directement connectées, si elles accèdent aux mêmes variables d'instance de la classe. n est le nombre de méthodes visibles menant à:

NP(C) = (n(n-1))/2 

et

TCC(C) = NDC(C)/NP(C) 

j'ai donc écrit une méthode qui parse par toutes les méthodes dans la classe que je veux vérifier. Cette méthode stocke toutes les méthodes de cette classe et il champs qu'ils utilisent dans un dictionnaire qui ressemble à ceci:

Dictionary<MethodDefinition, IList<FieldReference>> references = new Dictionary<MethodDefinition, IList<FieldReference>>(); 

Alors maintenant, comment puis-je itérer cette Dictionnary pour vérifier la condition mentionnée ci-dessus? Si je comprends bien, je dois trouver ces deux paires de méthodes qui utilisent le même ensemble de champs? Alors comment puis-je le faire de la meilleure façon? Je pense que je dois parcourir le dictionnaire et voir si le IList contient le même ensemble? (même pas dans le même ordre)?

Des idées ou des idées?

Mon code est le suivant, mais il ne fonctionne pas correctement:

class TCC 
    { 

     public static int calculate(TypeDefinition type) 
     { 
      int count = 0; 


      Dictionary<MethodDefinition, HashSet<FieldReference>> references = new Dictionary<MethodDefinition, HashSet<FieldReference>>(); 

      foreach (MethodDefinition method in type.Methods) 
      { 
       if (method.IsPublic) 
       { 
        references.Add(method, calculateReferences(method)); 
       } 
      } 

      for (int i = 0; i < references.Keys.Count; i++) 
      { 
       HashSet<FieldReference> list = new HashSet<FieldReference>(); 
       references.TryGetValue(references.Keys.ElementAt(i), out list); 

       if (isPair(references, list)) { 
        count++; 
       } 

      } 

      if (count > 0) 
      { 
       count = count/2; 
      } 

      return count; 
     } 

     private static bool isPair(Dictionary<MethodDefinition, HashSet<FieldReference>> references, HashSet<FieldReference> compare) 
     { 
      for (int j = 0; j < references.Keys.Count; j++) 
       { 
        HashSet<FieldReference> compareList = new HashSet<FieldReference>(); 
        references.TryGetValue(references.Keys.ElementAt(j), out compareList); 

        for (int i = 0; i < compare.Count; i++) 
        { 
         if (containsAllElements(compareList, compare)) { 
          return true; 
         } 
        } 
       } 

      return false; 
     } 

     private static bool containsAllElements(HashSet<FieldReference> compareList, HashSet<FieldReference> compare) 
     { 
      for (int i = 0; i < compare.Count; i++) 
      { 
       if (!compareList.Contains(compare.ElementAt(i))) 
       { 
        return false; 
       } 
      } 
      return true; 
     } 

     private static HashSet<FieldReference> calculateReferences(MethodDefinition method) 
     { 
      HashSet<FieldReference> references = new HashSet<FieldReference>(); 
      foreach (Instruction instruction in method.Body.Instructions) 
      { 
       if (instruction.OpCode == OpCodes.Ldfld) 
       { 
        FieldReference field = instruction.Operand as FieldReference; 
        if (field != null) 
        { 
         references.Add(field); 
        } 
       } 
      } 

      return references; 
     } 
    } 
+1

Combien de paires sont là si la clé A/B/C tous contiennent le même élément "MyItem"? –

+1

Est-ce pour .NET 2.0? (Le manque de var dans une déclaration verbeuse me rend suspect.) Si c'est le cas, alors il est important de le mentionner car vous pourriez obtenir beaucoup de réponses LINQ qui ne vous seront pas utiles. –

+0

J'ai modifié la question pour répondre aux commentaires. –

Répondre

1

Puisque vous ne nous avez pas dit comment on peut dire que deux FieldReference sont dupliquées, je vais utiliser la valeur par défaut.

version LINQ:

int duplicated = references.SelectMany(p => p.Value) 
          .GroupBy(x => x) 
          .Where(g => g.Count() > 1) 
          .Count(); 
+0

merci, j'ai ajouté un edit – RoflcoptrException

+0

Cela semble vraiment bien fonctionner! Pouvez-vous expliquer brièvement les pls? – RoflcoptrException

+0

@Roflcoptr: Toutes les méthodes sont [méthodes d'extension] (http://msdn.microsoft.com/en-us/library/bb383977.aspx) pour LINQ. –

1

Peut-on utiliser ContainsValue pour vérifier les doublons? D'après ce que vous avez décrit, il semble que vous ayez seulement des doublons si les valeurs sont identiques.

2

Eh bien, si vous ne me dérange pas garder un autre dictionnaire, nous pouvons frapper cette chose avec un grand-Durn-marteau. Tout simplement, si nous imaginons un dictionnaire où ordered_set (field-references) est la clé à la place, et nous gardons une liste des valeurs pour chaque touche .... Inutile de dire que ce n'est pas l'approche la plus intelligente, mais il est rapide, facile et utilise des structures de données que vous connaissez déjà.

EG:
hashset< hashset < FieldReference >, Ilist< methods >> Favorite_delicatessen

Build ReferenceSet for method
Look up ReferenceSet in Favorite_Delicatessen
If there:
Add method to method list
Else:
Add Referenceset,method pair

et votre liste des méthodes est donc la liste des méthodes qui partagent si vous me laissez un terme COÍN la même signature de l'Etat,.

+0

Il ne doit pas être très intelligent;) Il devrait juste fonctionner pour l'instant: D Si je vous comprends bien, vous passeriez juste la clé et la valeur? – RoflcoptrException

+0

Eh bien .... Oui, essentiellement. Assurez-vous que les références de champs sont triées, et je pense que vous voulez qu'elles soient un ensemble, à moins que je ne me trompe, puisque ce qui vous intéresse est "Est-ce que la fonction touche ceci?" pas "Est-il touché à plusieurs reprises?" –

+0

Oui, vous avez raison, ce n'est pas bien si l'accès répété aux champs existe aussi. J'ai utilisé un ensemble dans ma nouvelle solution (voir edit), mais je ne vois pas encore où utiliser votre suggestion – RoflcoptrException

1

Que diriez-vous d'obtenir un dictionnaire où la clé est l'élément en double, et la valeur est une liste de clés du dictionnaire original qui contiennent le double:

var dupes = references 
    .SelectMany(k => k.Value) 
    .GroupBy(v => v) 
    .Where(g => g.Count() > 1) 
    .ToDictionary(i => i.Key, i => references 
     .Where(f => f.Value.Contains(i.Key)) 
     .Select(o => o.Key)); 
Questions connexes