2010-06-06 4 views
11

Eventuali duplicati:
How do I assign by “reference” to a class field in c#?Come memorizzare un riferimento a un numero intero in C#?

Ciao a tutti - mi dicono come fare questo lavoro? Fondamentalmente, ho bisogno di un tipo di riferimento intero (int * funzionerebbe in 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' 
    } 
} 

Devo usare la boxe?

Modifica: Forse avrei dovuto essere più specifico. Sto scrivendo una classe BitAccessor, che consente semplicemente l'accesso a singoli bit. Ecco il mio utilizzo desiderata:

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

Usage:

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

Per BitAccessor per essere in grado di modificare m_val, ha bisogno di un riferimento ad esso. Ma voglio usare questo BitAccessor in molti posti, con solo un riferimento al numero intero desiderato.

+1

Qual è il tuo obiettivo qui? Questo è fondamentalmente contrario all'idea del codice gestito; se potessi memorizzare un ref in 'foo' in qualche altra classe la cui durata non è legata a' main', cosa succede quando si esce da 'main' e il frame dello stack in cui' foo' vive viene distrutto? – tzaman

+0

@tzaman, la mia modifica ha chiarito le mie intenzioni? @abatishchev - Mi piacerebbe, ma nessuna delle risposte fa esattamente quello che stavo cercando. Forse non è possibile. –

+0

Perché i puntatori non sicuri fanno ciò che stai cercando? Hai persino menzionato che i puntatori farebbero il trucco se questo fosse in C++. –

risposta

6

Non è possibile memorizzare un riferimento a un intero genere direttamente, ma si può negozio un riferimento all'oggetto GlorifiedInt che lo contiene. Nel tuo caso, ciò che probabilmente farei è rendere la classe BitAccessor nidificata all'interno di GlorifiedInt (in modo che possa accedere ai campi privati) e quindi passarla a this quando viene creata, che può quindi utilizzare per accedere allo m_val campo. Ecco un esempio che fa quello che stai cercando:

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

Grazie! Questo è quello che stavo cercando. E il tuo BitAccessor sembra identico a quello che ho scritto. L'unica cosa migliore sarebbe bello, sarebbe essere in grado di applicarlo a qualsiasi Integer - ma ciò non può essere fatto senza il riferimento. La tua soluzione funziona bene per lo scopo del mio progetto, tuttavia. –

+0

È possibile aggiungere anche questo: operatore implicito statico pubblico GlorifiedInt (int v) { return new GlorifiedInt (v); } Ciò consente di scrivere ad es. GlorifiedInt a = 10; – Henry

3

Non è necessario avere un riferimento a un numero intero: è sufficiente inserire il numero intero all'interno di un tipo di riferimento, che è quasi quello che hai già fatto. Basta cambiare questa linea:

Console.WriteLine(foo); 

a:

Console.WriteLine(bar.Value); 

Quindi aggiungere una funzione di accesso adeguato alla classe Bar, e rimuovere gli errori di compilazione (rimuovere le ref parole chiave).

Un approccio alternativo è quello di passare il numero intero a una funzione per riferimento:

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

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

uscita:

8 
+1

Nessuno di questi è esattamente quello che l'OP sta chiedendo, che sembra essere (se ho capito bene) un modo per * memorizzare * il ref al locale 'int foo' in' Main' all'interno dell'oggetto 'Bar', tale che _other_ richiami di metodo sull'istanza 'Bar' cambia il valore di' pippo' in 'Principale'. Non sono sicuro che sia effettivamente possibile in C#, senza entrare nel codice non sicuro ... – tzaman

+0

@tzaman, il primo è quello che l'OP sta chiedendo, comportamentale; ricorda che abbiamo sostituito l'uso di 'Main' di' foo' con 'bar.Value'. In realtà è solo la boxe manuale, che l'OP suggerisce che non vuole. –

-1

Lei non ha specificato che eri contro codice non sicuro, quindi questo dovrebbe funzionare:

unsafe class Bar { 
    private int* m_ref; 

    public Bar(int* val) { 
     m_ref = val; 
    } 

    public void AddOne() { 
     *m_ref += 1; 
    } 
} 

unsafe class Program { 
    static void Main() { 
     int foo = 7; 
     Bar b = new Bar(&foo); 
     b.AddOne(); 
     Console.WriteLine(foo); // prints 8 
     Console.ReadLine(); 
    } 
} 

non ho mai usato i puntatori in C#, ma sembra funzionare. Non sono sicuro di quali siano i possibili effetti collaterali.

+10

Sei * esplicitamente vietato * da questo. Devi * mai * memorizzare un riferimento a un puntatore dello stack come questo. Se il puntatore sopravvive dopo che il frame dello stack è sparito, accadono cose brutte. Ecco perché questo modello non è legale nel codice di sicurezza in primo luogo! ** Il codice non sicuro richiede di sapere quali sono TUTTI i possibili effetti collaterali; è per questo che non è sicuro. ** –

+0

Bene, imparo qualcosa di nuovo ogni giorno. Grazie per la spiegazione. :) –

-1

Questo non risponde direttamente alla tua domanda, ma si può non solo utilizzare la classe System.Collections.BitArray?

Ti chiedi solo se stai "reinventando la ruota"?

+0

per favore mostra come usare BitArray in questo scenario – devi