Neden bool / int döndüren ve gerçek nesneyi çıktı parametresi olarak içeren bir yönteminiz var?


12

Şirketimin kod tabanında (.NET 3.5 uygulaması) aşağıdaki kod desenini her yerde görüyorum:

bool Foo(int barID, out Baz bazObject) { 
    try { 
            // do stuff
            bazObject = someResponseObject;

            return true;
    }
    catch (Exception ex) { 
        // log error
        return false;
    }
}

// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);

if (baz != null) { 
    // do stuff with baz
}

Neden Fooyöntem yerine sadece ID almak ve Bazkullanılmayan bir değer döndürme ve gerçek nesne bir ref veya output parametresi olması yerine bir nesne döndürmek yerine bunu yapmak etrafında kafamı sarmaya çalışıyorum .

Eksik olduğum bu kodlama stilinin gizli bir yararı var mı?



Örnekte, bazvarlık nullve döndürülen boolvarlık falsevardır değil eşdeğeri. new BazObject()asla atılmaz null, bu yüzden atılmadan bazObjectönce güncellenmedikçe , ne zaman iade edilir asla . Eğer muazzam yardımcı olacağını Spec için kullanılabilir. Aslında, bu belki de bu kodun sergilediği en ciddi sorundur. ExceptionFoofalsebaznullFoo
Steve Powell

Bellek uzun zaman önce olduğu gibi puslu ama ben örnek berbat olduğunu düşünüyorum ve "baz" yanlış olup olmadığını kontrol ediyordu, boş değilse. Her durumda, desen VB6'dan olduğu gibi bana gerçekten arkaik görünüyordu ve geliştirici kodunu geliştirmek için hiç uğraşmadı (ki bunu yapmadı)
Wayne Molina

Yanıtlar:


11

Genellikle bu deseni kullanırsınız, böylece şöyle bir kod yazabilirsiniz:

if (Foo(barId, out bazObject))
{
  //DoStuff with bazobject
}

örneğin sözlük sınıfında TryGetValue için CLR'de kullanılır. Fazlalıktan kaçınır, ancak dışarı ve ref parametreleri her zaman biraz dağınık görünüyordu


1
+1, bu nedenle, her ikisini de ayrı ayrı döndürmek yerine hem boolean hem de nesne ile bir nesneyi döndürme eğilimindeyim
pdr

Oybirliği belirli durumlar dışında oldukça eski gibi görünse de, nedeni açıkladığı için bunu cevap olarak işaretleyecek.
Wayne Molina

Bu cevap, bu modelin kullanımını haklı çıkarır. Ama eğer kod tabanınızın TÜMÜ ise, muhtemelen Sean tarafı gibi kötü bir uygulamadır.
Codism

11

İstisnalar olmadan önce bu eski C stil kodu. Dönüş değeri, yöntemin başarılı olup olmadığını ve eğer öyleyse parametrenin sonuçla doldurulacağını belirtir.

.Net'te bu amaçla istisnalarımız var. Bu modeli takip etmek için hiçbir sebep olmamalıdır.

İstisna yönetiminde performansın etkileri olduğu açıktır. Belki de bununla bir ilgisi vardır. Ancak, bu kod snippet'inde zaten bir istisna var. Daha uygun bir yerde yakalanana kadar yığını yukarı hareket ettirmek daha temiz olurdu.


Hayır. Buna katılamıyorum. Beklenen bir koşul için asla bir istisna kullanmayın. Örneğin, bir dizgeyi bir int ile ayrıştırıyorsanız, birinin ayrılmaz bir dizeyi geçirmesi her zaman mümkündür. Bu durumda bir istisna atmamalısınız
pdr

Ben öyle demedim. OP tarafından gönderilen kodu okursanız, açıkça bir özel durum oluşur, ancak yöntem onu ​​yakalar ve bunun yerine false değerini döndürür. Bu soru, beklenen koşullarla değil, hata işlemeyle ilgilidir.
Sean Edwards

Evet, esas olarak veritabanından veri yükleyen yöntemlerde kullanılır gibi görünmektedir, if (baz.Select())ancak çoğu zaman dönüş değeri atılmaz ve değer null veya bazı özelliklere karşı kontrol edilir.
Wayne Molina

@Sean, ne dediğine bak, sadece ".NET'te bu amaç için istisnalarımız var" ifadesine itiraz ediyorum. İstisnalar benim için tamamen farklı bir amaca hizmet ediyor
pdr

1
Tamam, net olalım. Geçersiz argümanlarda kodlama hatalarını hesaba katmak için her yönteme yalnızca bir boole eklememeniz gerektiği doğrudur. Ancak , bir yöntemin girdisinin bir geliştiriciden ziyade bir kullanıcıdan geldiği durumlarda, girdiyi yanlış anlarsa bir istisna atmadan işlemeyi denemelisiniz.
pdr

2

Kod pasajı göz önüne alındığında tamamen anlamsız görünüyor. Bana göre ilk kod deseni BazObject için null değerinin kabul edilebilir bir durum olacağını ve bool dönüşünün başarısız bir durumu güvenli bir şekilde belirlemenin bir ölçüsü olduğunu düşündürür. Aşağıdaki kod şuysa:

// calling code
BazObject baz = new BazObject();
bool result = fooObject.Foo(barID, out baz);

if (result) { 
    // do stuff with baz
    // where baz may be 
    // null without a 
    // thrown exception
}

Bu benim bu şekilde yapmam daha anlamlı olur. Belki de bu, baz parametrelerinin aslında C # 'da nesne parametrelerinin nasıl çalıştığını anlamadan referansla iletildiğini garanti etmek için kullanmadan önce bir yöntemdir.


Bence ekibin şu anki bir üyesi tarafından yazıldı. Belki de O_O hakkında endişelenmem gereken bir şey
Wayne Molina

@Wayne M: Potansiyel bir eğitim fırsatından daha az endişe :)
Joel Etherton

1

Bazen bu model, arayan kişi olarak, döndürülen türün bir başvuru veya değer türü olup olmadığına dikkat etmeniz gerekmediğinde yararlıdır. Bir değer türünü almak için böyle bir yöntem çağırıyorsanız, bu değer türünün yerleşik bir geçersiz değere (ör. Double.NaN) veya başarıyı belirlemenin başka bir yoluna ihtiyacınız olacaktır.


Mantıklı. Biraz garip görünüyor, ama geçerli bir neden gibi geliyor.
Wayne Molina

0

Fikir, işlemin başarılı olup olmadığını gösteren bir değer döndürmektir.

Baz b;
if (fooObject.foo(id, out b)) {
   // do something with b
}
else {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

Nesne boş olamazsa (örneğinizde doğru görünür), aşağıdaki gibi daha iyi yapılır:

Baz b = fooObject.foo(id);
if (b != null) {
   // do something with b
}
else {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

Nesne null olabilirse , istisnalar gidilecek yollardır:

try {
   Baz b = fooObject.foo(id);
}
catch (BazException e) {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

İstisnaların olmadığı C'de kullanılan yaygın bir örüntüdür. Fonksiyonun bir hata koşulu döndürmesine izin verir. İstisnalar genellikle çok daha temiz bir çözümdür.


Özellikle kod zaten bir istisna atıyor beri.
David Thornley
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.