2010-06-06 5 views
11

Possible en double:
How do I assign by “reference” to a class field in c#?Comment stocker une référence à un entier en C#?

Bonjour à tous - me dire comment faire ce travail? Fondamentalement, je besoin d'un type de référence entier (int * travaillerait en C++)

class Bar 
{ 
    private ref int m_ref;  // This doesn't exist 

    public A(ref int val) 
    { 
     m_ref = val; 
    } 

    public void AddOne() 
    { 
     m_ref++; 
    } 
} 

class Program 
{ 
    static void main() 
    { 
     int foo = 7; 
     Bar b = new Bar(ref foo); 
     b.AddOne(); 
     Console.WriteLine(foo); // This should print '8' 
    } 
} 

Dois-je utiliser la boxe?

Modifier: Peut-être que j'aurais dû être plus précis. J'écris une classe BitAccessor, qui permet simplement d'accéder à des bits individuels. Voici mon utilisation souhaitée:

class MyGlorifiedInt 
{ 
    private int m_val; 
    ... 
    public BitAccessor Bits { 
     return new BitAccessor(m_val); 
    } 
} 

Utilisation:

MyGlorifiedInt val = new MyGlorifiedInt(7); 
val.Bits[0] = false;  // Bits gets a new BitAccessor 
Console.WriteLine(val); // outputs 6 

Pour BitAccessor pour pouvoir modifier m_val, il a besoin d'une référence. Mais je veux utiliser ce BitAccessor de nombreux endroits, avec juste une référence à l'entier désiré.

+1

Quel est votre objectif ici? Cela va fondamentalement à l'encontre de l'idée du code managé; si vous pouviez stocker une référence à 'foo' dans une autre classe dont la durée de vie n'est pas liée à' main', que se passe-t-il lorsque 'main' se termine et que le cadre de pile où' foo' vit est détruit? – tzaman

+0

@tzaman, est-ce que mon édition a éclairci mes intentions? @abatishchev - Je voudrais, mais aucune des réponses ne fait tout à fait ce que je cherchais. Peut-être que ce n'est pas possible. –

+0

Pourquoi les pointeurs dangereux ne feraient-ils pas ce que vous cherchez? Vous avez même mentionné que les pointeurs feraient l'affaire si c'était en C++. –

Répondre

6

Vous ne pouvez pas stocker une référence à un entier comme celui-ci directement, mais peut stocker une référence à l'objet GlorifiedInt le contenant. Dans votre cas, ce que je ferais probablement est de rendre la classe BitAccessor imbriquée à l'intérieur de GlorifiedInt (afin qu'elle ait accès aux champs privés), puis de lui passer une référence à this quand elle est créée, qu'elle peut alors utiliser pour accéder au m_val champ. Voici un exemple qui fait ce que vous cherchez:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var g = new GlorifiedInt(7); 
     g.Bits[0] = false; 
     Console.WriteLine(g.Value); // prints "6" 
    } 
} 

class GlorifiedInt 
{ 
    private int m_val; 

    public GlorifiedInt(int value) 
    { 
     m_val = value; 
    } 

    public int Value 
    { 
     get { return m_val; } 
    } 

    public BitAccessor Bits 
    { 
     get { return new BitAccessor(this); } 
    } 

    public class BitAccessor 
    { 
     private GlorifiedInt gi; 

     public BitAccessor(GlorifiedInt glorified) 
     { 
      gi = glorified; 
     } 

     public bool this[int index] 
     { 
      get 
      { 
       if (index < 0 || index > 31) 
        throw new IndexOutOfRangeException("BitAcessor"); 
       return (1 & (gi.m_val >> index)) == 1; 
      } 
      set 
      { 
       if (index < 0 || index > 31) 
        throw new IndexOutOfRangeException("BitAcessor"); 
       if (value) 
        gi.m_val |= 1 << index; 
       else 
        gi.m_val &= ~(1 << index); 
      } 
    } 
    } 
} 
+0

Merci! C'est ce que je cherchais. Et votre BitAccessor est identique à celui que j'avais écrit. La seule chose qui serait mieux, ce serait de pouvoir appliquer ceci à n'importe quel entier - mais cela ne peut pas être fait sans la référence. Votre solution fonctionne bien pour la portée de mon projet, cependant. –

+0

Vous pouvez également ajouter ceci: opérateur public statique implicite GlorifiedInt (int v) { return new GlorifiedInt (v); } Ceci vous permet d'écrire par ex. GlorifiedInt a = 10; – Henry

3

Vous n'avez pas besoin d'avoir une référence à un entier - il suffit de mettre votre entier dans un type de référence - ce qui est presque ce que vous avez déjà fait. Il suffit de changer cette ligne:

Console.WriteLine(foo); 

à:

Console.WriteLine(bar.Value); 

Ensuite, ajoutez un accesseur correspondant à la classe Bar et supprimer les erreurs de compilation (supprimer les mots-clés ref).

Une approche alternative est de passer l'entier à une fonction par référence:

static void AddOne(ref int i) 
{ 
    i++; 
} 

static void Main() 
{ 
    int foo = 7; 
    AddOne(ref foo); 
    Console.WriteLine(foo); 
} 

Sortie:

8 
+1

Ni l'un ni l'autre n'est exactement ce que demande OP, ce qui semble être (si je comprends bien) un moyen de * stocker * le ref du local 'int foo' dans' Main' dans l'objet 'Bar', tel que Les appels de méthode _other_ sur l'instance 'Bar' changent la valeur de' foo' dans 'Main'. Pas sûr que ce soit réellement possible en C#, sans entrer dans un code dangereux ... – tzaman

+0

@tzaman, le premier est ce que l'OP demande, comportementwise; rappelez-vous que nous avons remplacé l'utilisation de 'foo' par' Main' avec 'bar.Value'. Ce n'est vraiment que de la boxe manuelle, que l'OP suggère ne pas vouloir. –

-1

Vous ne précisaient pas que vous étiez contre le code dangereux, donc cela devrait fonctionner: Je n'ai jamais utilisé de pointeurs en C#, mais cela semble fonctionner. Je ne suis pas sûr de ce que les effets secondaires possibles sont.

+10

Vous êtes * explicitement interdit de le faire. Vous devez * jamais * stocker une référence à un pointeur de pile comme celui-ci. Si le pointeur survit après la fin du cadre de la pile, de mauvaises choses se produisent. C'est pourquoi ce modèle n'est pas légal dans un code de sécurité en premier lieu! ** Code dangereux exige que vous sachiez quels sont TOUS les effets secondaires possibles; C'est pourquoi c'est dangereux. ** –

+0

Eh bien, j'apprends quelque chose de nouveau chaque jour. Merci pour l'explication. :) –

-1

Cela ne répond pas directement à votre question, mais pouvez-vous pas seulement utiliser la classe System.Collections.BitArray?

Vous vous demandez simplement si vous «réinventez la roue»?

+0

s'il vous plaît montrer comment utiliser BitArray dans ce scénario – devi

Questions connexes