2009-07-20 11 views
10

Ref geçerken hala kafam karıştı.Ref geçiyor mu?

I nesnelerin bir dizi/mevcut erişilebilir isteyen bir önbellek nesne olması, ve yapıcı enjeksiyon kullanarak enjekte edin. Oluşturduğum tek önbellek nesnesini etkilemesini istiyorum. Örneğin.

public class Cache { 

    public void Remove(string fileToRemove) { 
     ... 
    } 
} 

public class ObjectLoader { 

    private Cache _Cache; 

    public ObjectLoader(Cache cache) { 

    } 

    public RemoveFromCacheFIleThatHasBeenDeletedOrSimilarOperation(string filename) { 
     _Cache.Remove(fileName); 
    } 
} 

Önbellekimi ObjectLoader yapıcısına iletirken ref kullanmalı mıyım? Referans işaret ediyor ne değiştirmek gerektiğinde

cevap

11

bakın bu durumda ref anahtar kelime kullanmak gerekmez Hayır.

Önbellek bir sınıftır, bir referans türüdür. Bir başvuru bir yönteme aktarıldığında, referansın bir kopyası (nesnenin kendisi değil) parametrenize yerleştirilir. Yöntemin iç ve dış her iki referansı da öbek üzerinde aynı nesneyi işaret eder ve nesnenin alanlarının birini kullanarak değiştirilmesi diğerine yansıtılır. senin yöntem çağrısına

ekleme ref orijinal referans geçer. Bu, yeniden atacağınız bir durumda faydalıdır (örn.new numaralı telefonu arayarak, referans noktasının arama yönteminin içinden geldiği yer.

7

'ref' anahtar kelime kullanın. Eğer değeri geçtiği bir yönteme, bir referans türü geçer, ama bir değer olduğunda bir yönteme geçirilir referans kopya. Bu, başvurulan nesnenin genel durumunu (yani, özelliklerini/alanlarını) değiştirebileceğiniz anlamına gelir, ancak referans noktalarının yalnızca kopyayı etkileyeceğini değiştirmeye çalışırsanız. Bu yöntem Verilen örnek için

...

private void Foo(MyClass obj) 
{ 
    obj = new MyClass(); 
    obj.SomeProperty = true; 
} 

Biz argüman geçmek ve etkilendi o zaman görebilirsiniz:

MyClass test = new MyClass(); 
test.SomeProperty = false; 
Foo(test); 
Console.WriteLine(test.SomeProperty); // prints "False" 

Şimdi kullanarak yöntemi tanımlanmış olsaydı, 'ref' anahtar kelimesi ...

private void Foo(ref MyClass obj) 
{ 
    obj = new MyClass(); 
    obj.SomeProperty = true; 
} 

Gerçek referans, yönteme iletildiğinden çıktı "True" olur. bir kopya değil. Bu referansın işlev içinde ne gösterdiğini değiştirdik ve bu değişikliklerin etkilerini görüyoruz. Eğer 'ref' anahtar kelimesini atladığınızda

sadece yığın üzerinde nesneye yeni bir işaretçi yaratıyor. Bir işaretçiyi değiştirirseniz, diğerini değiştirmezsiniz.

...

Sorunuza cevap vermek için; hayır, tek bir önbellek nesnesinin durumunu bir yönteme aktarıldığında değiştirmek için 'ref' anahtar sözcüğünü kullanmanız gerekmez. Onları .NET çerçevesinde, fonksiyon argümanları içinde değer geçirilecek beyan bile

+0

Normal C/C++ işaretçileri ile çok daha basit :) – Eugene

+1

Katılmıyorum :) Ama c/C++ insanlar için * (veya &) ve ** :) – Stormenet

+1

nitpick arasındaki fark: 2. örnek - siz statik bir özelliğe erişim. – Cherian

-3

Nesneler otomatik başvuruya göre iletilir. Nesnenin kendisi bir başvuru türü olduğu için nesneyi kendisi yerini alamaz halde nesnenin üyeleri değiştirebilir böylece

, buna bağlıdır.

http://msdn.microsoft.com/en-us/library/aa903253(VS.71).aspx

+6

Nesneler, diğer her şey gibi, değere göre geçirilir. Nesnelerle arasındaki fark (reads: reference types), REFERENCE değerine göre geçirilir. –

+2

Açık veya kapalı bir şekilde kullanmadığınız sürece, tüm parametreler C# cinsinden geçirilir. Ancak, referans türleri söz konusu olduğunda, kopyalanmış referans aynı örneğe işaret eder, böylece örneği değiştirebilir, ancak referansın kendisini değiştiremezsiniz. –

1

Sana Cache nesnenin birçok kopya oluşturuldu alacak merak düşünüyorum. Birden çok istemci nesnesi tarafından yalnızca bir kopyanın paylaşılmasını istiyorsunuz. Nesnenizin kaç kopyasının oluşturulacağını bilmek istediğinizde C# 'da hatırlayabileceğiniz çok basit bir kural var. new anahtar kelime ile:

nesnenin tip ile class anahtar kelime ilan edilirse, o zaman yeni bir örneğini yapmak için tek bir yolu vardır. Nesneleri oluşturmak BCL yöntemlerini çağırabilir, ama mesele o açık olmasıdır:

bu ufak çaplı istisnası yoktur. Bunun olmasını özellikle istemelisiniz. Dil, otomatik olarak class nesnenin kopyasını oluşturmaz.

Yani örnekte, bir class Cache denilen var ve siz istediğiniz kadar ve Cache ait başka kopya oluşturulacak tip Cache değişkenlerini dolaşması gerekiyor böylece kesin olarak biliyoruz. Onlara atanan nesneye sahip olan tüm değişkenler aynı orijinal nesneye "işaret eder". Bir Cache değişken nesneyi kendisi ama bellekte bir Cache nesnenin sadece konumunu saklamaz olmasıdır. bunun yerine class bir struct türü bildirmek ne olur bu

Kontrast. Eğer bu tür bir değişkeni bildirmek Şimdi, değişken kendisi struct beyan tüm veri depolamak için yeterli büyüklükte olmalıdır. Her değişken ayrı bir kopyadır. Her parametre ayrı bir kopyadır.

Sen ref anahtar kelime ekleyerek bu geçersiz kılabilir, ancak çoğu programlarında oldukça alışılmadık kelime bu. out anahtar sözcüğü daha yaygındır ve bir yönteme birden fazla dönüş değeri vermenin bir yolu olarak düşünülür.

o class türü ise ref bir değişken üzerinde ne gibi etkisi? Örnekte:

public ObjectLoader(Cache cache) { 
    // do stuff with cache (store it?) 
} 

böyle iki nesne yükleyiciler olustursaydiniz:

Cache c = new Cache(); 
ObjectLoader a = new ObjectLoader(c), 
ObjectLoader b = new ObjectLoader(c); 

biz sadece kaç nesneleri yarattı? Sadece new anahtar kelimeleri sayın. Şimdi, biz ref anahtar kelime eklendi varsayalım:

public ObjectLoader(ref Cache cache) { 

    _cache = cache; // store   

    // do something very odd! 
    cache = new Cache(); 
} 

o kurucu içinde, başka bir önbellek oluşturduk Gizli ve ben geçirildi parametrede depoladı. Bu bir ref parametresi olduğundan, arayanın değişkenini etkiledim! arama kodunda Yani: Yukarıdaki kod parçasında üç artı modifiye ObjectLoader kurucusuna iki çağrı:

Cache c = new Cache(); 
ObjectLoader a = new ObjectLoader(ref c), 
ObjectLoader b = new ObjectLoader(ref c); 

Şimdi new beş kullanımları vardır. Her zaman ObjectLoader yapıcısı çağrılır, biz c iletiriz. Biz kod okuma kişi garip bir şey oluyor bilirler çünkü çok iyi bir şeydir ref anahtar kelimeyi koymak zorunda.c değişkeni, ObjectLoader yapıcısının döndürülmesinden sonra farklı bir Cache işaret eder. Yani b 's ObjectLoader bir işaretçiyi a için Cache farklı bir yere depolamak kadar biter!

Söylemeye gerek yok, bu kod için oldukça dağınık bir desen olurdu. Çağıran sitede ref anahtar kelimesini koymak zorunda kalmazsak daha da kötü olur!