2010-06-06 23 views
11

Olası Çoğalt:
How do I assign by “reference” to a class field in c#?C# içindeki bir tamsayıya nasıl başvuru yapılır?

Merhaba herkes - nasıl bu işi yapmak için söyle? Temelde,

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' 
    } 
} 

Ben boks kullanmak zorunda mı (* C++ çalışacak int) tamsayı referans türüne ihtiyacınız?

Düzenleme: Belki de daha spesifik olmalıydım. Ben sadece bireysel bitlere erişime izin veren bir BitAccessor sınıfı yazıyorum. İşte benim istenen kullanımı:

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

Kullanımı:

BitAccessor m_val değiştirmeye muktedir için
MyGlorifiedInt val = new MyGlorifiedInt(7); 
val.Bits[0] = false;  // Bits gets a new BitAccessor 
Console.WriteLine(val); // outputs 6 

, bunun bir başvuru gerekiyor. Ancak, bu BitOccessor'u birçok yerde kullanmak istiyorum, sadece istenen tamsayıya referansla.

+1

Amacınız nedir? Bu temelde yönetilen kod fikrine karşı çıkıyor; eğer yaşamı 'ana' ile bağlantılı olmayan başka bir sınıfta bir 'foo'yu saklayabilseydiniz,' ana 'çıktığında ne olur ve' foo 'nun yaşadığı yığın çerçevesi ne olur? – tzaman

+0

@tzaman, düzenlemelerim niyetimi açıkladı mı? @abatishchev - Ben isterdim, ama cevapların ikisi de tam olarak aradığım şeyi yapmaz. Belki bu mümkün değildir. –

+0

Neden güvensiz işaretçiler aradığınızı yapıyor? C++ 'da olsaydı göstericilerin hile yapmasını bile söylediniz. –

cevap

6

Doğrudan böyle bir tamsayıya ait bir referansı saklayamazsınız, ancak sizde kodunu içeren GlorifiedInt nesnesine bir başvuru kaydedebilirsiniz. Sizin durumunuzda, muhtemelen yapmam gereken BitAccessor sınıfının GlorifiedInt içine girmesini (böylece özel alanlara erişebilmesini) sağlamaktır ve daha sonra oluşturulduğunda this referansını iletir, daha sonra m_val'a erişmek için kullanabilirsiniz alan. İşte bir örnek aradığınız yapar ki var:

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

Teşekkür ederiz! Aradığım şey bu. Ve senin BitOccessor yazdığımla aynı görünüyor. Bu daha iyi olan tek şey, bunu herhangi bir Tamsayıya uygulayabilmek olacaktır - ancak bu referans olmadan yapılamaz. Ancak çözümünüz projem kapsamı için iyi çalışıyor. –

+0

Ayrıca şunları da ekleyebilirsiniz: public static implicit operator GlorifiedInt (int v) { yeni döndürülen GlorifiedInt (v); } Bu, örn. GlorifiedInt a = 10; – Henry

3

Bir tamsayıya başvurmanıza gerek yoktur - tamsayılarınızı bir referans türüne sokmanız yeterlidir; bu, neredeyse yaptığınız şeydir. Sonra sınıfa Bar uygun bir erişimci eklemek

Console.WriteLine(bar.Value); 

ve derleme hataları (ref kelimeyi uzaklaştırmak) kaldırın:

Console.WriteLine(foo); 

için: Sadece bu satırı değiştirin.

alternatif bir yaklaşım referans olarak bir işleve tamsayı geçmektir:

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

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

Çıktı:

8 
+1

Bunların hiçbiri tam olarak OP'nin sorduğu şeydir, ki bu doğrudur (eğer doğru anlıyorsam) * bir şekilde * saklamak için bir yoldur * “Bar” nesnesinin içindeki “Ana” içindeki yerel “int foo” ye ref; "Bar" örneğinde _other_ yöntem çağrıları, "Ana" öğesindeki "foo" değerini değiştirir. Güvenli olmayan kodlara girmeden C# 'da gerçekten mümkün olduğundan emin değilsiniz ... – tzaman

+0

@tzaman, birincisi OP'nin sorgusuzdur; 'Main'un 'foo' işlevini bar.Value' ile değiştirdiğimizi unutmayın. OP'in istemediğini öne sürdüğü, gerçekten sadece manuel boks. –

-1

Sen güvensiz kod karşıydı belirtmedi, bu nedenle bu çalışması gerekir:

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(); 
    } 
} 

C# işaretçileri kullanmamıştım, ancak işe yarayacak gibi görünüyor. Olası yan etkilerin ne olduğundan emin değilim.

+10

Bunu yapmaktan * açıkça yasak * kaldınız. Bunun gibi bir yığın işaretçisine bir başvuru * kaydetmemelisiniz. Yığın çerçevesi bittikten sonra işaretçi hayatta kalırsa, kötü şeyler olur. Bu yüzden bu model ilk etapta güvenli kodda yasal değildir! ** Güvenli olmayan kod, TÜM olası yan etkilerin neler olduğunu bilmenizi gerektirir; Bu yüzden güvensiz. ** –

+0

Her gün yeni bir şeyler öğreniyorum. Açıklama için teşekkürler. :) –

-1

Bu doğrudan cevap vermez, ama sadece System.Collections.BitArray sınıfını kullanabilir?

Sadece "tekerleği yeniden icat edip etmediğinizi" merak ediyor musunuz?

+0

, bu senaryoda BitArray'i nasıl kullanacağınızı lütfen gösteriniz – devi

İlgili konular