Çalışma zamanında ref ve out arasındaki fark nedir?


15

C # refve outbaşvuru ile iletilecek argümanlar yapmak için anahtar kelimeyi sağlar. İkisinin semantiği çok benzer. Tek fark, flaged değişkenin başlatılmasıdır:

  • refdeğişkenin işleve geçirilmeden önce başlatılmasını gerektirir, outdeğil.
  • outdeğişkenin fonksiyonun içinde başlatılmasını gerektirir, refyapmaz.

Bu iki anahtar kelimenin kullanım durumları da hemen hemen aynıdır ve çok sık kullanımları, bir kod kokusu olarak kabul edilir ( TryParseve TryGetValuekalıpları gibi geçerli kullanım durumları olmasına rağmen ).

Bu nedenle birisi açıklayabilir, neden bu kadar dar kullanım durumları için C # 'da iki benzer araç var?

Ayrıca, MSDN'de farklı çalışma zamanı davranışlarına sahip oldukları belirtilir:

Ref ve out anahtar sözcükleri farklı çalışma zamanı davranışlarına neden olsa da, derleme zamanında yöntem imzasının bir parçası olarak değerlendirilmezler.

Çalışma zamanı davranışları nasıl farklıdır?

Sonuç

Her iki cevap da doğru görünüyor, ikinize de teşekkürler. Jmoreno'ları kabul ettim çünkü daha açık.


Benim tahminim her ikisi de refC ++ ile aynı şekilde uygulanır ; söz konusu nesne işaretçisine (veya ilkel) işaret etmek için. yani Int32.TryParse(myStr, out myInt)(C #), (C) 'nin yaptığı gibi "yürütülür" int32_tryParse(myStr, &myInt); tek fark, hataların önlenmesi için derleyici tarafından uygulanan bazı kısıtlamalardır. (Bunu cevap olarak vermeyeceğim, çünkü bunun perde arkasında nasıl çalıştığı konusunda yanılıyor olabilirim, ancak bu şekilde çalışmasını öngörüyorum [çünkü mantıklı])
Cole Johnson

Yanıtlar:


10

Bu soru sorulduğunda, MSDN makalesi ustaca yanlıştı (o zamandan beri düzeltildi ). "Farklı davranışlara neden olmak" yerine "farklı davranışlar gerektirir" olmalıdır.

Özellikle, aynı mekanizma (IL) davranışı etkinleştirmek için kullanılmasına rağmen, derleyici iki anahtar kelime için farklı gereksinimleri uygular.


Benim anlayışım, derleyicinin bir outparametrenin kaydı silme veya parametre atamama gibi şeyleri kontrol etmesidir ref, ancak yaydığı IL her iki şekilde de bir referanstır. Bu doğru mu?
Andrew

Btw, tek olmasından bu söyleyebilir out Tve ref Tbu tür VB.Net veya C ++ / CLI gibi diğer CLI dillerinde benzer duruma getirilir.
ach

@AndrewPiliser: doğru. Kodun her iki şekilde de derlendiğini varsayarsak (yapmamanız gerektiğinde referanstan ayrılmaya çalışmazsınız), IL aynı olur.
jmoreno

4

konuyla ilgili sorunuza cevap verebilecek ilginç bir yazı:

http://www.dotnetperls.com/ref

ilgi konusu:

"Ref ve out arasındaki fark Ortak Dil Çalışma Zamanı'nda değil C # dilinin kendisidir."

Güncelleme:

İşimdeki kıdemli geliştirici @ jmoreno'nun cevabını destekledi, bu yüzden okuduğunuzdan emin olun !.


Yani doğru anlarsam, IL seviyesinde fark yoktur, bu da onların farklı çalışma süresi davranışlarına sahip olamayacaklarını ima eder. Bu, MSDN'nin söyledikleriyle çelişir. Yine de ilginç bir makale!
Gábor Angyal

@ GáborAngyal tesadüfen MSDN makalesine bir bağlantınız yok mu? Görüşler farklıysa burada olması güzel olabilir
Dan Beaulieu


1
Bütün bunlarla ne stringilgisi var?
Robert Harvey

Makaleden sadece bir açıklama. İkinci satırı kaldırmak için güncellendi ..
Dan Beaulieu

2

Çalışma zamanı ? Kesinlikle yok. Yalnızca ref veya out anahtar sözcüğüyle farklı olan aynı parametrelere sahip bir yöntemi aşırı yükleyemezsiniz.

Bunu derlemeye çalışın ve "Aynı imzayla yöntem zaten bildirildi" derleme hatası alırsınız:

    private class MyClass
    {
        private void DoSomething(out int param)
        {
        }
        private void DoSomething(ref int param)
        {
        }
    }

Bu soruyu cevaplamak için: "... neden C # 'da bu kadar dar kullanım durumlarında çok benzer iki araç var?"

Kod okunabilirliği ve API açısından büyük bir fark var. API'nin bir tüketicisi olarak "out" kullanıldığında API'nın out parametresine bağlı olmadığını biliyorum. API geliştiricisi olarak "çıkış" ı tercih ediyorum ve "ref" yi yalnızca (nadiren) gerekli olduğunda kullanıyorum. Harika bir tartışma için bu referansa bakın:

/programming/1516876/when-to-use-ref-vs-out

Destekleyici bilgi: Aşağıdaki yöntemi derledim ve söktüm. (Bu örnekte) ref ve out anahtar kelimeleri kullandım, ancak beklediğim gibi bir adres başvurusu dışında derleme kodu değişmedi:

    private class MyClass
    {
        internal void DoSomething(out int param)
        {
            param = 0;
        }
    }

00000000 itme ebp
00000001 mov ebp, esp
00000003 itme edi
00000004 itme esi
00000005 itme ebx
00000006 alt esp, 34h 00000009
xor eax, eax
0000000b mov dword ptr [ebp-10h], eax
0000000e mov dword ptr [ebp-1Ch], eax
0000000e mov dword ptr [ebp-3Ch], ecx
00000014 mov dword ptr [ebp-40h], edx
00000017 cmp dword ptr ds: 0
0000001e je 00000025
00000020 çağrı 6E6B601E
00000025 nop
param = 0;
00000026 mov eax, dword ptr [ebp-
40h ] 00000029 xor edx, edx
0000002b mov dword ptr [eax], edx
}
0000002d nop
0000002e lea esp, [ebp-0Ch]
00000031 pop ebx 00000032 pop
esi
00000033 pop edi
00000034 pop ebp 00000035
ret

Düzeneği doğru okuyor muyum?


Yazdıklarınız doğrudur, ancak bu aşırı yüklemeye izin verilmediği için çalışma zamanı farkı olmadığının açık bir ima olmadığını lütfen unutmayın.
Gábor Angyal

Ahh - güzel nokta! Herkes yukarıdaki kodu söküp doğru ya da yanlış olduğunu kanıtlayabilir mi? Meclisi okurken korkunçum, ama merak ediyorum.
Shmoken

Tamam - "out" ve "ref" kullanarak kodu
söktüm ve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.