Bagaimana Anda bisa menggunakan parameter opsional di C #?


493

Catatan: Pertanyaan ini ditanyakan pada saat C # belum mendukung parameter opsional (yaitu sebelum C # 4).

Kami sedang membangun API web yang dihasilkan secara programatis dari kelas C #. Kelas memiliki metode GetFooBar(int a, int b)dan API memiliki metode yang GetFooBarmengambil params permintaan seperti &a=foo &b=bar.

Kelas perlu mendukung parameter opsional, yang tidak didukung dalam bahasa C #. Apa pendekatan terbaik?


7
Atau tunggu unitil C # 4.0 dirilis. Parameter opsional didukung.
Mikha

Jawaban:


1055

Terkejut tidak ada yang menyebutkan parameter opsional C # 4.0 yang berfungsi seperti ini:

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

Sunting: Saya tahu bahwa pada saat pertanyaan itu diajukan, C # 4.0 tidak ada. Tapi pertanyaan ini masih menduduki peringkat # 1 di Google untuk "argumen opsional C #" jadi saya pikir - jawaban ini layak berada di sini. Maaf.


58
Pada saat pertanyaan diajukan, C # 4.0 tidak ada.
Forrest Marvez

91
Yap, lupakan ini, maaf. Namun pertanyaan ini masih menempati urutan # 1 di Google untuk "argumen opsional C #" - jawaban ini layak ada di sini :)
Alex

45
Bagus untuk Anda karena memberikan informasi terkini. Idealnya jawaban asli akan diperbarui dengan informasi terkini seperti C # 4.0. Saya percaya itulah yang awalnya dipikirkan oleh orang-orang itu, mentalitas Wiki, tetapi semua orang agak terlalu takut untuk mengedit jawaban orang lain.
Rowan

Sesuatu yang menarik yang saya temukan dengan WebServices adalah (tentu saja dalam proyek yang saya uji) semua nilai bool dalam querystring adalah opsional secara default. Jelas mereka default ke FALSE.
Carlos P

4
Perlu dicatat bahwa parameter opsional harus ditempatkan setelah semua parameter non-opsional. yaitu Anda tidak dapat membatalkan public SomeMethod (int b = 0, int a)
Andrew Meservy

129

Pilihan lain adalah menggunakan kata kunci params

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

Disebut seperti ...

DoSomething(this, that, theOther);

57
Jawaban ini menjelaskan kata kunci params dengan cantik dalam 10 baris, MSDN masih gagal melakukannya dalam 30. +1
User2400

1
Terima kasih! Ini mengilhami saya untuk menulis fungsi logging sederhana (untuk kasus penggunaan saya saat ini): 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(); }Contoh panggilan:log("...Done,",(watch.ElapsedMilliseconds/1000).ToString(),"s");
pfonseca

dapatkah Anda menyebutkan, apakah net 3.5 mendukungnya? dokumen resmi tidak menyebutkan itu.
T.Todua

@ T.Todua - Saya tidak 100% yakin apa yang Anda minta di sini - dotnet framework 3.5 termasuk C # v3.0 - versi 3.0 memang mendukung kata kunci params, tetapi tidak memiliki parameter opsional, yang diperkenalkan dalam C # v4.0 , yang termasuk dalam kerangka dotnet 4.0
Tim Jarvis

@TimJarvis ya, itu yang saya minta. tnx
T.Todua

77

Dalam C #, saya biasanya menggunakan beberapa bentuk metode:

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

UPDATE: Ini disebutkan di atas adalah cara saya melakukan nilai default dengan C # 2.0. Proyek yang saya kerjakan sekarang menggunakan C # 4.0 yang sekarang secara langsung mendukung parameter opsional. Ini adalah contoh yang baru saja saya gunakan dalam kode saya sendiri:

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

1
Saya percaya Anda tidak dapat memanggil konstruktor dalam parameter default, mereka perlu "kompilasi-waktu" yang kompatibel, bukan "run-time" ... Atau apakah saya salah?
Alex

45

Dari situs ini:

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

C # memungkinkan penggunaan atribut [Opsional] (dari VB, meskipun tidak berfungsi dalam C #). Jadi Anda dapat memiliki metode seperti ini:

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

Di bungkus API kami, kami mendeteksi parameter opsional (ParameterInfo p.IsOptional) dan menetapkan nilai default. Tujuannya adalah untuk menandai parameter sebagai opsional tanpa menggunakan kludges seperti memiliki "opsional" dalam nama parameter.


4
Tapi bagaimana cara menggunakan fungsi Foo? Foo (1,1); foo (1,1, null) dan foo (1,1, Missing.value) semuanya akan melempar pengecualian
Bolu

2
Aneh, Beberapa jawaban di atas jauh lebih baik dari ini.
Pembantu

26

Anda dapat menggunakan metode kelebihan ...

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

Tergantung pada tanda tangan metode, contoh yang saya berikan tidak memiliki metode "int b" saja karena akan memiliki tanda tangan yang sama dengan metode "int a".

Anda dapat menggunakan jenis Nullable ...

GetFooBar (int? A, int? B)

Anda kemudian dapat memeriksa, menggunakan Nilai., Untuk melihat apakah suatu parameter telah ditetapkan.

Opsi lain adalah menggunakan parameter 'params'.

GetFooBar (objek params [] args)

Jika Anda ingin menggunakan parameter bernama perlu membuat tipe untuk menanganinya, meskipun saya pikir sudah ada sesuatu seperti ini untuk aplikasi web.


24

Anda dapat menggunakan parameter opsional di C # 4.0 tanpa khawatir. Jika kita memiliki metode seperti:

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

ketika Anda memanggil metode, Anda dapat melewati parameter seperti ini:

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

C # 4.0 mengimplementasikan fitur yang disebut "parameter bernama", Anda benar-benar dapat melewati parameter dengan nama mereka, dan tentu saja Anda dapat melewati parameter dalam urutan apa pun yang Anda inginkan :)


20

Halo Dunia Opsional

Jika Anda ingin runtime memberikan nilai parameter default, Anda harus menggunakan refleksi untuk melakukan panggilan. Tidak sebagus saran lain untuk pertanyaan ini, tetapi kompatibel dengan VB.NET.

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

Cara mudah yang memungkinkan Anda menghilangkan parameter apa pun di posisi apa pun , adalah memanfaatkan jenis yang dapat dibatalkan sebagai berikut:

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("-");
}

String sudah merupakan tipe yang dapat dibatalkan sehingga mereka tidak membutuhkannya ? .

Setelah Anda memiliki metode ini, semua panggilan berikut ini valid :

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

Ketika Anda mendefinisikan suatu metode dengan cara itu Anda memiliki kebebasan untuk mengatur hanya parameter yang Anda inginkan dengan memberi nama mereka. Lihat tautan berikut untuk informasi lebih lanjut tentang parameter bernama dan opsional:

Bernama dan Argumen Opsional (Panduan Pemrograman C #) @ MSDN


9

Saya setuju dengan stephenbayer. Tetapi karena ini adalah layanan web, lebih mudah bagi pengguna akhir untuk menggunakan hanya satu bentuk metode web, daripada menggunakan beberapa versi dari metode yang sama. Saya pikir dalam situasi ini Jenis Nullable sempurna untuk parameter opsional.

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 Kata nasihat sekalipun. Jangan menjadikan ini kebiasaan karena bisa jadi sangat berantakan.
mhenrixon

7

parameter opsional untuk metode. jika Anda memerlukan argumen opsional untuk suatu kelas dan Anda adalah:

  • menggunakan c # 4.0: gunakan argumen opsional dalam konstruktor kelas, solusi yang saya sukai, karena lebih dekat dengan apa yang dilakukan dengan metode, jadi lebih mudah diingat. ini sebuah contoh:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
  • menggunakan versi c # sebelumnya ke c # 4.0: Anda harus menggunakan chaining konstruktor (menggunakan: kata kunci ini), di mana konstruktor yang lebih sederhana mengarah ke "master konstruktor". contoh:

    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

Cara khas ini ditangani dalam C # seperti langkah yang disebutkan adalah untuk membebani metode. Dengan membuat beberapa versi metode dengan berbagai parameter Anda secara efektif membuat parameter opsional. Dalam formulir dengan parameter yang lebih sedikit, Anda biasanya akan memanggil formulir metode dengan semua parameter yang menetapkan nilai default Anda dalam panggilan ke metode itu.


2

Anda dapat membebani metode Anda secara berlebihan. Satu metode berisi satu parameter GetFooBar(int a)dan yang lainnya berisi kedua parameter,GetFooBar(int a, int b)


2

Menggunakan kelebihan beban atau menggunakan C # 4.0 atau lebih tinggi

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

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

1

Untuk sejumlah besar parameter opsional, satu parameter Kamus dapat digunakan dengan metode ContainsKey. Saya suka pendekatan ini karena memungkinkan saya untuk lulus Daftar atau T secara individual tanpa harus membuat metode lain (misalnya parameter yang bagus digunakan sebagai filter).

Contoh (Kamus baru <string, Obyek> () akan diteruskan jika tidak ada parameter opsional yang diinginkan):

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

0

Alih-alih parameter default, mengapa tidak hanya membangun kelas kamus dari querystring berlalu .. implementasi yang hampir identik dengan cara bentuk asp.net bekerja dengan querystrings.

yaitu Request.QueryString ["a"]

Ini akan memisahkan kelas daun dari kode pabrik / boilerplate.


Anda juga mungkin ingin memeriksa Layanan Web dengan ASP.NET . Layanan web adalah api web yang dihasilkan secara otomatis melalui atribut pada kelas C #.


0

Sedikit terlambat ke pesta, tetapi saya sedang mencari jawaban untuk pertanyaan ini dan akhirnya menemukan cara lain untuk melakukan ini. Deklarasikan tipe data untuk argumen opsional metode web Anda menjadi tipe XmlNode. Jika arg opsional dihilangkan, ini akan disetel ke nol, dan jika ada, Anda bisa mendapatkan nilai string dengan memanggil arg.Value, yaitu,

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

Apa yang juga layak tentang pendekatan ini adalah halaman beranda .NET yang dihasilkan untuk ws masih menampilkan daftar argumen (meskipun Anda kehilangan kotak entri teks berguna untuk pengujian).


3
Apakah ini lebih baik daripada menggunakan tipe yang dapat dibatalkan?
Kirk Broadhurst

0

Saya memiliki layanan web untuk menulis yang membutuhkan 7 parameter. Masing-masing adalah atribut kueri opsional ke pernyataan sql yang dibungkus oleh layanan web ini. Jadi dua solusi untuk param non-opsional muncul dalam pikiran ... keduanya sangat buruk:

method1 (param1, param2, param 3, param 4, param 5, param 6, param7) method1 (param1, param2, param3, param 4, param5, param 6) metode 1 (param1, param2, param3, param4, param5, param7, param7 ) ... mulai melihat gambar. Dengan cara ini ada kegilaan. Terlalu banyak kombinasi.

Sekarang untuk cara yang lebih sederhana yang terlihat canggung tetapi harus bekerja: method1 (param1, bool useParam1, param2, bool useParam2, dll ...)

Itu satu panggilan metode, nilai untuk semua parameter diperlukan, dan itu akan menangani setiap kasus di dalamnya. Juga jelas cara menggunakannya dari antarmuka.

Ini hack, tapi itu akan berhasil.


2
Inilah sebabnya mengapa parameter nullable ada.
Kirk Broadhurst

0

Saya harus melakukan ini di VB.Net 2.0 Web Service. Saya akhirnya menetapkan parameter sebagai string, lalu mengubahnya menjadi apa pun yang saya butuhkan. Parameter opsional ditentukan dengan string kosong. Bukan solusi terbersih, tetapi berhasil. Berhati-hatilah agar Anda menangkap semua pengecualian yang dapat terjadi.


0

Untuk berjaga-jaga jika seseorang ingin meneruskan panggilan balik (atau delegate) sebagai parameter opsional, dapat melakukannya dengan cara ini.

Parameter Panggilan Balik opsional:

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

parameter opsional tidak lain adalah parameter default! saya sarankan Anda memberikan keduanya parameter default. GetFooBar (int a = 0, int b = 0) jika Anda tidak memiliki metode kelebihan beban, akan menghasilkan a = 0, b = 0 jika Anda tidak melewati nilai apa pun, jika Anda melewati nilai 1, akan menghasilkan , nilai lulus untuk a, 0 dan jika Anda melewati 2 nilai 1 akan ditugaskan ke a dan kedua ke b.

berharap itu menjawab pertanyaan Anda.


0

Dalam kasus ketika nilai-nilai default tidak tersedia, cara untuk menambahkan parameter opsional adalah dengan menggunakan kelas .NET OptionalAttribute - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute ? view = netframework-4.8

Contoh kode di bawah ini:

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

Anda dapat mencoba ini juga
Tipe 1
public void YourMethod(int a=0, int b = 0) { //some code }


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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.