C # 4.0 isteğe bağlı çıkış / ref bağımsız değişkenleri


212

C # 4.0 isteğe bağlı outveya refbağımsız değişkenlere izin veriyor mu?


2
Weell, C ++ etkin bir şekilde "dışarı" parametreleri için onlara sahiptir - null olarak başlatılmış bir adres bağımsız değişkenine sahip olabilirsiniz ve yalnızca işaretçi boş değilse bu tür bir dönüş yapısını dolduracak kütüphane kodu yazmak oldukça yaygındır. Bu, C API'larındaki "isteğe bağlı bağımsız değişkenler" için null değerinin kullanılmasına geri dönen bir deyimdir.
Andy Dent

53
@Ed ve herkes: bunun neden bir anlamı yok? Bir işlev "out" üzerinden "değer" döndürürse, onu kabul etmek zorunda kalmak istemiyorum. Şimdi, teknik nedenlerden dolayı derleyicinin hala bir şey geçirmesi gerektiğini biliyorum, ancak arkamdan sadece benim için bir kukla yerel oluşturmamasının bir nedeni yok.
Roman Starkov

5
Belki işlerin nasıl uygulandığı ya da isteğe bağlı bir parametrenin gerçekte ne olduğu anlamsızdır. Ancak romkyns'ın dediği gibi, "isteğe bağlı dışarıda argümanlara" sahip olmak gerçekten güzel olurdu - bunu CLR yerine İngilizce olarak ayrıştırın ve makul ve IMO'da arzu edilir hale gelir.
Adam Tolley

9
C # değil, VB.NET yapar.
Jason

5
Bu ölümle dövüldü, ancak, isteğe bağlı tartışmalara destek verdiğimden bahsetmiyorum. Ben bir nullvarsayılan ( PHP gelen ) ve referans null( tanıdık olanlar için düşünmekpreg_match() ) tartışma devam etmek için test yoluyla referans ile isteğe bağlı argümanlar alışkın oldum Her neyse, ben şu anda teknik bir noktadan anlıyorum imkansız, ve PHP ve C # oldukça kıyaslanabilir değil, hala mevcut olması " güzel " bir araç olurdu .
Dan Lugg

Yanıtlar:


93

Daha önce de belirtildiği gibi, buna izin verilmiyor ve bence çok mantıklı. Ancak, daha fazla ayrıntı eklemek için, C # 4.0 Şartnamesi , bölüm 21.1'den bir alıntı :

Yapıcıların, yöntemlerin, dizinleyicilerin ve delege türlerinin resmi parametreleri isteğe bağlı olarak bildirilebilir:

fixed-parametre:
    öznitelikler opt parametre-değiştirici opt tür tanımlayıcı default-argüman opt
default-argüman:
    = ifade

  • Bir sabit parametreli bir ile varsayılan-değişken bir bir isteğe bağlı bir parametre , bir oysa sabit parametre a olmadan varsayılan-değişken a, gerekli parametre .
  • Gerekli bir parametre, Resmi bir parametre listesindeki .
  • A refveya outparametrenin varsayılan bağımsız değişkeni olamaz .

Alternatif olarak, bir ref / out parametresiyle aşırı yük oluşturabilirsiniz. Evet, iki işlev tanımınız olacak, ancak peşinde olduğunuz şeyi başaracak
Çad

201

Hayır.

Çözüm, out / ref parametrelerine sahip olmayan ve yalnızca geçerli yönteminizi çağıran başka bir yöntemle aşırı yüklenmektir .

public bool SomeMethod(out string input)
{
    ...
}

// new overload
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

Güncelleme: C # 7.0'ınız varsa, basitleştirebilirsiniz:

// new overload
public bool SomeMethod()
{
    return SomeMethod(out _);    // declare out as an inline discard variable
}

(Bunu işaret ettiği için @Oskar / @Reiner'a teşekkürler.)


6
temp / kukla ilan etmekten daha zarif bir çözüm için herhangi bir fikir?
Louis Rhys

20
Bu konuda zarif olmayan ne var? Bana çok yakışmış görünüyor.
Neutrino

27
Belki iyi, ama zarif kesinlikle başka bir ligde. Daha iyi bir çözüm olmaması, bunun kararname ile son teknoloji olduğu anlamına gelmez.
o0 '.

7
@ O0 'basılı tutun. C # 7.0 bunu yapmak mümkün olacaktır: return SomeMethod(out string temp). Burada daha fazlasını görün: blogs.msdn.microsoft.com/dotnet/2016/08/24/…
Oskar

7
C # 7.0 gibi geçici bir salt okunur değişken kullanabilirsiniz:return SomeMethod(out _);
Reiner

64

Hayır, ancak başka bir harika alternatif, yöntemin isteğe bağlı parametreler için genel bir şablon sınıfı kullanmasıdır:

public class OptionalOut<Type>
{
    public Type Result { get; set; }
}

Sonra aşağıdaki gibi kullanabilirsiniz:

public string foo(string value, OptionalOut<int> outResult = null)
{
    // .. do something

    if (outResult != null) {
        outResult.Result = 100;
    }

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    OptionalOut<int> optional = new OptionalOut<int> ();

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);

    // example: call it with named optional parameter
    foo (str, outResult: optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);
}

19
Bu çok makul bir çözüm, ancak dikkat edilmesi gereken bir şey, derleyicinin yöntemden çıkmadan önce out parametresinin atanması gereksinimini zorlamamasıdır.
Ken Smith

2
Hoşuma gitti, ancak yeni bir sınıf oluşturmak istemiyorsanız, tek bir öğe dizisi geçirerek simüle edebilirsiniz.
zumalifeguard

30

Aslında bunu yapmanın bir yolu var C # tarafından izin verilir. Bu, C ++ 'a geri döner ve daha ziyade C #' ın güzel Nesne Odaklı yapısını ihlal eder.

BU YÖNTEMİ DİKKATLİ KULLANIN!

İsteğe bağlı bir parametreyle işlevinizi bildirme ve yazma yönteminiz şunlardır:

unsafe public void OptionalOutParameter(int* pOutParam = null)
{
    int lInteger = 5;
    // If the parameter is NULL, the caller doesn't care about this value.
    if (pOutParam != null) 
    { 
        // If it isn't null, the caller has provided the address of an integer.
        *pOutParam = lInteger; // Dereference the pointer and assign the return value.
    }
}

Sonra işlevi şöyle çağırın:

unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.

Bunu derlemek için proje seçeneklerinde güvenli olmayan kodu etkinleştirmeniz gerekir. Bu genellikle kullanılmaması gereken gerçekten çılgın bir çözümdür, ancak garip, gizemli, gizemli, yönetimden ilham alan bir karar için, C # 'da GERÇEKTEN isteğe bağlı bir çıkış parametresine ihtiyacınız varsa, bu sadece bunu yapmanıza izin verecektir.


6

ICYMI: Burada numaralandırılan C # 7.0'ın yeni özelliklerine dahil olan "disards " artık umursadığınız parametreleri göz ardı etmenize izin vermek için _ biçiminde out parametreleri olarak izin verilir:

p.GetCoordinates(out var x, out _); // I only care about x

PS, ayrıca "out var x" parçasıyla karıştırılırsanız, bağlantıdaki "Out Değişkenleri" hakkındaki yeni özelliği de okuyun.


_ veya * "p.GetCoordinates (out int x, out *); // sadece x umurumda"
Onur Topal

belgenin eski bir sürümünü arıyordum.
Onur Topal

2

Hayır, ancak bir temsilci kullanabilirsiniz (ör. Action ) alternatif olarak kullanabilirsiniz.

Kısmen Robin R'nin isteğe bağlı bir çıkış parametresi istediğimi düşündüğüm bir durumla karşılaştığında verdiği yanıttan esinlenerek bunun yerine bir Actiondelege kullandım . Ben Action<int>farklılıkları ve benzerlikleri göstermek için kullanmak için değiştirmek için onun örnek kod ödünç aldım :

public string foo(string value, Action<int> outResult = null)
{
    // .. do something

    outResult?.Invoke(100);

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    int optional = 0;

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);

    // example: call it with named optional parameter
    foo (str, outResult: x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);
}

Bu, isteğe bağlı değişkenin kaynakta normal bir int olarak görünmesi avantajına sahiptir (derleyici bunu kullanıcı tanımlı bir sınıfta açıkça sarmak yerine bir kapatma sınıfına sarar).

Derleyici Action, işlev çağrısı çıkmadan önce çağrının yapılamayacağını kabul edemediğinden, değişkenin açık başlatılması gerekir .

Tüm kullanım durumları için uygun değildir, ancak gerçek kullanım durumum için iyi çalıştı (bir birim test için veri sağlayan ve yeni bir birim testin dönüş değerinde olmayan bazı dahili durumlara erişilmesi gereken bir işlev).


0

C # 6.0 ve altı için out parametresine sahip olanı çağırmak için out parametresi olmadan aşırı yüklenmiş bir yöntem kullanın. Neden bir C # 7.0 .NET Core için özellikle C # 4.0 isteğe bağlı bir çıkış parametresi olabilir olup olmadığını sordu bile bu iş parçacığı için doğru cevap olduğundan emin değilim. Cevap hayır!


-2

Buna ne dersin?

public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
    return true;
}

C # parametresine hala bir değer iletmeniz gerekir, ancak isteğe bağlı bir ref parametresidir.


8
“C # parametresine yine de bir değer iletmeniz gerekiyor” ... Bu isteğe bağlı değil.
Arturo Torres Sánchez

C # [Optional]ek açıklamayı yoksayar . Bu yardımcı olmuyor.
ToolmakerSteve

-4
void foo(ref int? n)
{
    return null;
}

1
Herkesin kavramı kolayca anlamasını sağlamak için lütfen kodunuza biraz açıklama ekleyin
techspider

1
Bu kod soruyu cevaplayabilse de, soruyu neden ve / veya nasıl cevapladığı konusunda ek bağlam sağlamak uzun vadeli değerini önemli ölçüde artıracaktır. Lütfen biraz açıklama eklemek için cevabınızı düzenleyin .
Toby Speight

2
Yöntem geçersiz dönüş türüne sahip olduğundan sözdizimi hatasına neden olur. Ayrıca, soruya cevap vermez.
Nathan Montez
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.