C # 'da isteğe bağlı parametreleri nasıl kullanabilirsiniz?


493

Not: Bu soru, C # 'ın henüz isteğe bağlı parametreleri (yani C # 4'ten önce) desteklemediği bir zamanda sorulmuştur.

Programlı olarak bir C # sınıfından oluşturulan bir web API'sı oluşturuyoruz. Sınıfın yöntemi GetFooBar(int a, int b)ve API GetFooBargibi sorgu parametrelerini alan bir yöntemi vardır &a=foo &b=bar.

Sınıfların C # dilinde desteklenmeyen isteğe bağlı parametreleri desteklemesi gerekir. En iyi yaklaşım nedir?


7
Veya C # 4.0 biriminde bekleyin. İsteğe bağlı parametreler desteklenir.
Micah

Yanıtlar:


1055

Hiç kimse böyle çalışan C # 4.0 isteğe bağlı parametrelerden bahsetmedi:

public void SomeMethod(int a, int b = 0)
{
   //some code
}

Düzenleme: Sorunun sorulduğu anda, C # 4.0 olmadığını biliyorum. Ancak bu soru Google'da hala "C # isteğe bağlı bağımsız değişkenler" için 1. sırada yer aldığını düşündüm, bu yüzden düşündüm - bu cevap burada olmaya değer. Afedersiniz.


58
Soru sorulduğunda, C # 4.0 yoktu.
Forrest Marvez

91
Evet, bunu gözardı et, üzgünüm. Ancak bu soru yine de Google'da "C # isteğe bağlı bağımsız değişkenler" için 1. sırada yer alıyor - yine de bu cevap burada olmaya değer :)
Alex

45
Güncel bilgi sağladığınız için iyi. İdeal olarak orijinal cevaplar C # 4.0 gibi güncel bilgilerle güncellenir. Bence SO'ların aklında olan şey bu, bir Wiki zihniyeti, ama herkes bir başkasının cevabını düzenlemek için biraz fazla korkuyor.
Rowan

WebServices ile keşfettiğim ilginç bir şey (kesinlikle test ettiğim projede) bir sorgu dizesindeki tüm bool değerlerinin varsayılan olarak isteğe bağlı olmasıdır. Açıkçası varsayılan olarak YANLIŞ.
Carlos P

4
İsteğe bağlı parametrelerin, isteğe bağlı olmayan tüm parametrelerden sonra yerleştirilmesi gerektiğini belirtmek gerekir. Yani herkese açık bir boşluktan yararlanamazsınız SomeMethod (int b = 0, int a)
Andrew Meservy

129

Başka bir seçenek de params anahtar sözcüğünü kullanmaktır

public void DoSomething(params object[] theObjects)
{
  foreach(object o in theObjects)
  {
    // Something with the Objects…
  }
}

Şöyle denir ...

DoSomething(this, that, theOther);

57
Bu cevap params anahtar kelimesini 10 satırda güzel açıklar, MSDN hala 30'da yapamaz. +1
User2400

1
Teşekkürler! Bu bana basit (şimdiki kullanım durumum için) bir kayıt fonksiyonu yazmak için ilham verdi: public void log (params object[] args){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < args.Length; i++){ sb.Append("{"); sb.Append(i.ToString()); sb.Append("}"); sb.Append(" "); } String.Format(sb.ToString(),args).Dump(); }Örnek çağrı:log("...Done,",(watch.ElapsedMilliseconds/1000).ToString(),"s");
pfonseca

Net 3.5 bunu destekliyor mu? Resmi dokümanlar bundan bahsetmedi.
T.Todua

@ T.Todua - Burada sorduğunuzdan% 100 emin değilim - dotnet framework 3.5 dahil C # v3.0 - sürüm 3.0 params anahtar sözcüğünü destekledi, ancak C # v4.0'da tanıtılan isteğe bağlı parametreler yoktu , dotnet framework 4.0'a dahil edildi
Tim Jarvis

@TimJarvis evet, bunu istiyordum. tnx
T.Todua

77

C #, normalde yöntemin birden çok formunu kullanırdım:

void GetFooBar(int a) { int defaultBValue;  GetFooBar(a, defaultBValue); }
void GetFooBar(int a, int b)
{
 // whatever here
}

GÜNCELLEME: Yukarıda bahsedilen bu, C # 2.0 ile varsayılan değerleri yaptığım şekilde oldu. Şu anda üzerinde çalıştığım projeler artık isteğe bağlı parametreleri doğrudan destekleyen C # 4.0 kullanıyor. İşte kendi kodumda kullandığım bir örnek:

public EDIDocument ApplyEDIEnvelop(EDIVanInfo sender, 
                                   EDIVanInfo receiver, 
                                   EDIDocumentInfo info,
                                   EDIDocumentType type 
                                     = new EDIDocumentType(EDIDocTypes.X12_814),
                                   bool Production = false)
{
   // My code is here
}

1
Yapıcıları varsayılan parametrelerde çağıramazsınız, "derleme zamanı" ile uyumlu olmaları gerekir, "çalışma zamanı" değil ... Yoksa yanılıyor muyum?
Alex

45

Bu siteden:

http://www.tek-tips.com/viewthread.cfm?qid=1500861&page=1

C #, [İsteğe Bağlı] özniteliğinin kullanımına izin verir (C # 'da işlevsel olmasa da VB'den). Yani böyle bir yöntem olabilir:

using System.Runtime.InteropServices;
public void Foo(int a, int b, [Optional] int c)
{
  ...
}

API paketleyicimizde isteğe bağlı parametreleri (ParameterInfo p.IsOptional) tespit eder ve varsayılan bir değer belirleriz. Amaç, parametre adında "isteğe bağlı" olması gibi kludlara başvurmadan parametreleri isteğe bağlı olarak işaretlemektir.


4
Peki Foo işlevi nasıl kullanılır? Foo (1,1); foo (1,1, null) ve foo (1,1, Kayıp değer) istisnalar atacak
Bolu

2
Tuhaf, Yukarıdaki bazı cevaplar bundan çok daha iyi.
Maidot

26

Aşırı yükleme yöntemini kullanabilirsiniz ...

GetFooBar ()
GetFooBar (int a)
GetFooBar (int a, int b)

Yöntem imzalarına bağlıdır, verdiğim örnekte yalnızca "int b" yöntemi eksiktir, çünkü "int a" yöntemiyle aynı imzayı kullanır.

Null olabilecek türleri kullanabilirsiniz ...

GetFooBar (int? A, int? B)

Daha sonra, bir parametrenin ayarlanıp ayarlanmadığını görmek için a.HasValue kullanarak kontrol edebilirsiniz.

Başka bir seçenek de 'params' parametresini kullanmak olacaktır.

GetFooBar (params nesnesi [] argümanlar)

Adlandırılmış parametrelerle gitmek isterseniz, web uygulamaları için böyle bir şey olduğunu düşünüyorum, ancak bunları işlemek için bir tür oluşturmanız gerekir.


24

Endişelenmeden C # 4.0'da isteğe bağlı parametreleri kullanabilirsiniz. Gibi bir yöntemimiz varsa:

int MyMetod(int param1, int param2, int param3=10, int param4=20){....}

yöntemi çağırdığınızda, aşağıdaki gibi parametreleri atlayabilirsiniz:

int variab = MyMethod(param3:50; param1:10);

C # 4.0 "adlandırılmış parametreler" adı verilen bir özelliği uygular, parametreleri adlarına göre aktarabilir ve elbette parametreleri istediğiniz sırada aktarabilirsiniz :)


20

Merhaba İsteğe Bağlı Dünya

Çalışma zamanının varsayılan bir parametre değeri sağlamasını istiyorsanız, arama yapmak için yansıma kullanmanız gerekir. Bu sorunun diğer önerileri kadar hoş değil, ancak VB.NET ile uyumlu.

using System;
using System.Runtime.InteropServices;
using System.Reflection;

namespace ConsoleApplication1
{
    class Class1
    {
        public static void sayHelloTo(
            [Optional,
            DefaultParameterValue("world")] string whom)
        {
            Console.WriteLine("Hello " + whom);
        }

        [STAThread]
        static void Main(string[] args)
        {
            MethodInfo mi = typeof(Class1).GetMethod("sayHelloTo");
            mi.Invoke(null, new Object[] { Missing.Value });
        }
    }
}

16

Eğer çıkarmanıza olanak sağlar kolay bir yolu herhangi bir parametreyi de her pozisyonda , yararlanıyorsa null türleri şöyle:

public void PrintValues(int? a = null, int? b = null, float? c = null, string s = "")
{
    if(a.HasValue)
        Console.Write(a);
    else
        Console.Write("-");

    if(b.HasValue)
        Console.Write(b);
    else
        Console.Write("-");

    if(c.HasValue)
        Console.Write(c);
    else
        Console.Write("-");

    if(string.IsNullOrEmpty(s)) // Different check for strings
        Console.Write(s);
    else
        Console.Write("-");
}

Dizeler zaten null olabilecek türlerdir, bu yüzden ? .

Bu yöntemi kullandıktan sonra, aşağıdaki çağrıların tümü geçerlidir :

PrintValues (1, 2, 2.2f);
PrintValues (1, c: 1.2f);
PrintValues(b:100);
PrintValues (c: 1.2f, s: "hello");
PrintValues();

Bir yöntemi bu şekilde tanımladığınızda, yalnızca istediğiniz parametreleri adlandırarak ayarlama özgürlüğüne sahip olursunuz . Adlandırılmış ve isteğe bağlı parametreler hakkında daha fazla bilgi için aşağıdaki bağlantıya bakın:

Adlandırılmış ve İsteğe Bağlı Bağımsız Değişkenler (C # Programlama Kılavuzu) @ MSDN


9

Stephenbayer ile aynı fikirdeyim. Ancak bir web hizmeti olduğu için, son kullanıcının aynı yöntemin birden çok sürümünü kullanmaktan ziyade web yönteminin yalnızca bir biçimini kullanması daha kolaydır. Bence bu durumda Nullable Türleri isteğe bağlı parametreler için mükemmeldir.

public void Foo(int a, int b, int? c)
{
  if(c.HasValue)
  {
    // do something with a,b and c
  }
  else
  {
    // do something with a and b only
  }  
}

+1 Yine de tavsiye kelimesi. Bunu gerçekten alışkanlık haline getirmeyin çünkü gerçekten dağınık olabilir.
mhenrixon

7

isteğe bağlı parametreler yöntemler içindir. bir sınıf için isteğe bağlı bağımsız değişkenlere ihtiyacınız varsa ve siz:

  • c # 4.0 kullanarak: sınıfın yapıcısında isteğe bağlı argümanlar kullanın, tercih ettiğim bir çözüm, çünkü yöntemlerle yapılanlara daha yakın, hatırlanması çok daha kolay. İşte bir örnek:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
  • c # 4.0'dan önceki c # sürümlerini kullanarak: daha basit kurucuların bir "ana kurucu" ya yol açtığı kurucu zincirini (: bu anahtar sözcüğü kullanarak) kullanmalısınız. misal:

    class myClass
    {
        public myClass()
        {
        // this is the default constructor
        }
    
        public myClass(int myInt)
            : this(myInt, "whatever")
        {
            // do something here if needed
        }
        public myClass(string myString)
            : this(0, myString)
        {
            // do something here if needed
        }
        public myClass(int myInt, string myString)
        {
            // do something here if needed - this is the master constructor
        }
    }

3

Belirtilen stefen olarak bunun C # ile ele alınmasının tipik yolu, yöntemi aşırı yüklemektir. Yöntemin farklı parametrelerle birden çok sürümünü oluşturarak isteğe bağlı parametreleri etkili bir şekilde oluşturursunuz. Daha az parametreli formlarda, genellikle, bu yönteme yapılan çağrıda tüm parametrelerin varsayılan değerlerinizi ayarladığı yöntem formunu çağırırsınız.


2

Yönteminizi aşırı yükleyebilirsiniz. Bir yöntem bir parametre GetFooBar(int a)ve diğeri her iki parametreyi içerir,GetFooBar(int a, int b)


2

Aşırı yükleri kullanma veya C # 4.0 veya üstü kullanma

 private void GetVal(string sName, int sRoll)
 {
   if (sRoll > 0)
   {
    // do some work
   }
 }

 private void GetVal(string sName)
 {
    GetVal("testing", 0);
 }

1

Çok sayıda isteğe bağlı parametre için, ContainsKey yöntemiyle tek bir Sözlük parametresi kullanılabilir. Ben bu yaklaşımı seviyorum çünkü bana bir başka bir yöntem oluşturmak zorunda kalmadan tek tek bir Liste veya T geçmesine izin verir (parametreler filtre olarak kullanılacaksa güzel).

Örnek (isteğe bağlı parametre istenmezse yeni Sözlük <string, Object> () geçirilir):

public bool Method(string ParamA, Dictionary<string,Object> AddlParams) {
    if(ParamA == "Alpha" && (AddlParams.ContainsKey("foo") || AddlParams.ContainsKey("bar"))) {
        return true;
    } else {
        return false;
    }
}

0

Varsayılan parametreler yerine, neden sadece sorgu dizesi bir sözlük sınıfı oluşturmak değil .. asp.net formları sorgu dizeleri ile çalışma şekli ile neredeyse aynı bir uygulama.

ie Request.QueryString ["a"]

Bu, yaprak sınıfını fabrika / kazan plakası kodundan ayırır.


ASP.NET ile Web Hizmetlerine de göz atmak isteyebilirsiniz . Web hizmetleri, C # sınıflarındaki öznitelikler aracılığıyla otomatik olarak oluşturulan bir web API'sidir.


0

Partiye biraz geç kaldım, ama bu sorunun cevabını arıyordum ve sonuçta bunu yapmanın başka bir yolunu buldum. Web yönteminizin isteğe bağlı argümanlarının veri türlerini XmlNode türü olarak bildirin. İsteğe bağlı arg atlanırsa, bu null olarak ayarlanır ve varsa arg.Value çağırarak dize değeridir.

[WebMethod]
public string Foo(string arg1, XmlNode optarg2)
{
    string arg2 = "";
    if (optarg2 != null)
    {
        arg2 = optarg2.Value;
    }
    ... etc
}

Bu yaklaşımla ilgili iyi olan şey, ws için .NET tarafından oluşturulan ana sayfanın hala argüman listesini göstermesidir (test için kullanışlı metin giriş kutularını kaybetmenize rağmen).


3
Bu, null olabilecek türleri kullanmaktan daha mı iyidir?
Kirk Broadhurst

0

7 parametre alır yazmak için bir web hizmeti var. Her biri, bu web hizmeti tarafından sarılmış bir sql deyiminin isteğe bağlı bir sorgu özelliğidir. Yani isteğe bağlı olmayan parametreler için iki çözüm akla geliyor ... ikisi de oldukça zayıf:

yöntem1 (param1, param2, param5, param 4, param 5, param 6, param7) ) ... resmi görmeye başlayın. Bu şekilde delilik yatar. Çok fazla kombinasyon.

Şimdi garip görünen ama işe yarayacak daha basit bir yol için: method1 (param1, bool useParam1, param2, bool useParam2, vb ...)

Bu bir yöntem çağrısıdır, tüm parametreler için değerler gereklidir ve içindeki her durumu işleyecektir. Arayüzden nasıl kullanılacağı da açıktır.

Bu bir hack, ama işe yarayacak.


2
Bu nedenle nullable parametreleri vardır.
Kirk Broadhurst

0

Bunu bir VB.Net 2.0 Web Hizmeti'nde yapmak zorunda kaldım. Parametreleri dizeler olarak belirledim, sonra onları istediğim her şeye dönüştürdüm. Boş bir dize ile isteğe bağlı bir parametre belirtildi. En temiz çözüm değil, ama işe yaradı. Oluşabilecek tüm istisnaları yakaladığınıza dikkat edin.


0

Birisi delegateisteğe bağlı bir parametre olarak bir geri çağırma (veya ) iletmek istiyorsa , bunu bu şekilde yapabilir.

İsteğe bağlı Geri Arama parametresi:

public static bool IsOnlyOneElement(this IList lst, Action callbackOnTrue = (Action)((null)), Action callbackOnFalse = (Action)((null)))
{
    var isOnlyOne = lst.Count == 1;
    if (isOnlyOne && callbackOnTrue != null) callbackOnTrue();
    if (!isOnlyOne && callbackOnFalse != null) callbackOnFalse();
    return isOnlyOne;
}

0

isteğe bağlı parametreler varsayılan parametrelerden başka bir şey değildir! ikisine de varsayılan parametreleri vermenizi öneririm. Aşırı yüklenmiş bir yönteminiz yoksa GetFooBar (int a = 0, int b = 0), herhangi bir değer iletmezseniz a = 0, b = 0 ile sonuçlanır, 1 değerini geçerseniz, , a, 0 için geçen değer ve 2 değerini geçerseniz 1. a ve saniye b'ye atanır.

Umarım sorunuzu cevaplar.


0

Varsayılan değerlerin kullanılamaması durumunda isteğe bağlı parametre eklemenin yolu .NET OptionalAttribute sınıfını kullanmaktır - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute ? görünüşüdür = netframework-4,8

Kod örneği aşağıdadır:

namespace OptionalParameterWithOptionalAttribute
{
    class Program
    {
        static void Main(string[] args)
        {
            //Calling the helper method Hello only with required parameters
            Hello("Vardenis", "Pavardenis");
            //Calling the helper method Hello with required and optional parameters
            Hello("Vardenis", "Pavardenis", "Palanga");
        }
        public static void Hello(string firstName, string secondName, 
            [System.Runtime.InteropServices.OptionalAttribute] string  fromCity)
        {
            string result = firstName + " " + secondName;
            if (fromCity != null)
            {
                result += " from " + fromCity;
            }
            Console.WriteLine("Hello " + result);
        }

    }
}

-4

Bunu da deneyebilirsiniz
Tip 1
public void YourMethod(int a=0, int b = 0) { //some code }


Tip 2
public void YourMethod(int? a, int? b) { //some code }

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.