2009-12-31 7 views
4

J'ai couru à travers la classe suivante dans une API graphique C# XNA et je ne suis pas sûr de ce qu'il fait ou qu'il doit être si obscur. (T est contraint d'être un struct dans une classe parente)Que fait le code C# suivant?

static class Ident 
    { 
     static object sync = new object(); 
     static volatile int index = 0; 
     static int Index 
     { 
      get 
      { 
       lock (sync) 
        return index++; 
      } 
     } 
     class Type<T> 
     { 
      public static int id = Index; 
     } 
     public static int TypeIndex<T>() 
     { 
      return Type<T>.id; 
     } 
    } 

L'API fait uniquement sur appel à cette classe statique: int index = Ident.TypeIndex<T>();

Répondre

8

Cela crée un identificateur entier unique pour chaque type, en fonction de l'ordre dans lequel il est accédé, d'une manière thread-safe.

Par exemple, si vous faites:

int myClassId = Ident.TypeIndex<MyClass>(); 
int mySecondClssId = Ident.TypeIndex<MySecondClass>(); 

Vous obtiendrez 2 "TypeIndex" numéros (avec mySecondClassId étant au moins 1 plus de myClassId, mais potentiellement plus, en raison de filetage). Plus tard, si vous l'appelez de nouveau avec la même classe, il retournera le même TypeIndex pour cette classe.

Par exemple, si je lance ce, en utilisant:

Console.WriteLine(Ident.TypeIndex<Program>()); 
Console.WriteLine(Ident.TypeIndex<Test>()); 
Console.WriteLine(Ident.TypeIndex<Program>()); 
Console.WriteLine(Ident.TypeIndex<Test>()); 

Il imprimera:

0 
1 
0 
1 

Cependant, cela pourrait être fait en utilisant plus efficacement Interlocked.Increment, ce qui éviterait la nécessité de verrouiller et l'objet de synchronisation complètement. Ce qui suit donne exactement la même réponse, sans verrouillage nécessaire:

static class Ident 
{ 
    static int index = -1; 
    static int Index 
    { 
     get 
     { 

      return Interlocked.Increment(ref index); 
     } 
    } 
    private static class Type<T> 
    { 
     public static int id = Index; 
    } 

    public static int TypeIndex<T>() 
    { 
     return Type<T>.id; 
    } 
} 
+1

+1 pour une meilleure alternative – Diadistis

+1

Curieux - pourquoi la downvotation? –

+0

Spéculation - Ignorance – Diadistis

2

Il retourne le nombre de fois Ident.TypeIndex a été appelé, probablement affecter un numéro unique à chaque objet. En raison de la façon dont ils utilisent des génériques, il devrait y avoir une séquence de nombres différente pour chaque type T. Ainsi, vous pourriez avoir un cercle # 1, un cercle # 2 et un carré # 1.

+0

Nice ... le code pourrait utiliser certains commentaires à coup sûr. –

+3

En fait - ce n'est pas vrai. Vous obtenez un int unique pour chaque type, car chaque type utilise un seul ID statique. Vous n'obtenez pas une nouvelle séquence par type. –

+3

Si vous appelez cela, vous obtiendrez 0: Cercle, 0: Cercle, 1: Carré, 0: Cercle, etc ... –

8

Il attribue pour chaque type T.

exemple un identifiant unique à l'échelle d'application (statique) et du fil de sécurité (verrouillage d'objet de synchronisation + index volatile):

Console.WriteLine(Ident.TypeIndex<int>()); // 0 
Console.WriteLine(Ident.TypeIndex<string>()); // 1 
Console.WriteLine(Ident.TypeIndex<long>()); // 2 
Console.WriteLine(Ident.TypeIndex<int>()); // 0 

de matières volatiles est utilisé pour vous assurer que le thread actuel ne met pas en cache la valeur de l'index et que le verrouillage empêche plus d'un thread d'y accéder.

+3

+1 pour la mention des implications de filetage. –