Як можна використовувати необов'язкові параметри в C #?


493

Примітка. Це запитання задавали в той момент, коли C # ще не підтримував необов'язкові параметри (тобто перед C # 4).

Ми будуємо веб-API, програмно створений із класу C #. У класі є метод, GetFooBar(int a, int b)а в API є метод, що GetFooBarприймає параметри запитів &a=foo &b=bar.

Класи повинні підтримувати необов'язкові параметри, які не підтримуються мовою C #. Який найкращий підхід?


7
Або зачекайте, поки випущено одиницю C # 4.0. Необов’язкові параметри підтримуються.
Міхе

Відповіді:


1054

Здивував, що ніхто не згадав додаткові параметри C # 4.0, які працюють так:

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

Редагувати: Я знаю, що на момент запитання, C # 4.0 не існувало. Але це питання все ще займає №1 в Google за "C # необов'язковими аргументами", тому я подумав - ця відповідь варта бути тут. Вибачте.


58
На момент запитання, C # 4.0 не існувало.
Форрест Марвес

91
Так, вибачте з цього, вибачте. Але це питання все ще займає №1 в Google за "C # необов'язковими аргументами", так чи інакше - ця відповідь вартий бути тут :)
Alex

45
Добре від вас за надання актуальної інформації. В ідеалі оригінальні відповіді будуть оновлені поточною інформацією, такою як C # 4.0. Я вважаю, що це, на думку хлопців, спочатку мали на увазі, менталітет Вікі, але всі трохи бояться редагувати чужу відповідь.
Роуан

Щось цікаве, що я виявив за допомогою WebServices, - це те, що (безумовно, в проекті, який я тестую) усі значення bool у запиті рядків за замовчуванням необов’язкові. Очевидно, вони за замовчуванням до ЛЖУ.
Карлос П

4
Варто зазначити, що необов'язкові параметри повинні бути розміщені після всіх необов'язкових параметрів. тобто ви не можете мати публічну недійсність SomeMethod (int b = 0, int a)
Andrew Meservy

129

Інший варіант - використовувати ключове слово params

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

Називається як ...

DoSomething(this, that, theOther);

57
Ця відповідь пояснює парами ключове слово прекрасно в 10 рядках, MSDN все ще не вдається зробити це через 30. +1
User2400

1
Дякую! Це надихнуло мене написати просту (для мого поточного випадку використання) функцію ведення журналу: 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(); }Зразок виклику:log("...Done,",(watch.ElapsedMilliseconds/1000).ToString(),"s");
pfonseca

Ви можете сказати, чи підтримує чистий 3.5? офіційні документи цього не згадували.
Т.Тодуа

@ T.Todua - Я не на 100% впевнений, що ви тут запитуєте - dotnet Framework 3.5 включав C # v3.0 - версія 3.0 підтримувала ключове слово params, але не мала додаткових параметрів, що було введено в C # v4.0 , яка була включена в dotnet Framework 4.0
Тім Джарвіс

@TimJarvis так, це я просив. tnx
Т.Тодуа

77

У C # я зазвичай використовую кілька форм методу:

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

ОНОВЛЕННЯ: Це згадане вище було тим, що я робив значення за замовчуванням за допомогою C # 2.0. Проекти, над якими я зараз працюю, використовують C # 4.0, який зараз безпосередньо підтримує необов’язкові параметри. Ось приклад, який я щойно використав у власному коді:

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

1
Я вважаю, що ви не можете викликати конструкторів за параметрами за замовчуванням, їм потрібно "час компіляції" сумісний, а не "час виконання" ... Або я помиляюся?
Олексій

45

З цього сайту:

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

C # дозволяє використовувати атрибут [Необов’язково] (від VB, хоча і не функціонує в C #). Тож у вас може бути такий метод:

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

У нашій обгортці API ми виявляємо необов’язкові параметри (ParameterInfo p.IsO optional) і встановлюємо значення за замовчуванням. Мета полягає в тому, щоб позначити параметри як необов'язкові, не вдаючись до помилок, як-от "імператор" у назві параметра.


4
Але як потім використовувати функцію Foo? Foo (1,1); foo (1,1, null) і foo (1,1, Missing.value) будуть кидати винятки
Bolu

2
Дивно, але деякі відповіді вище набагато кращі за це.
Майдот

26

Ви можете використовувати метод перевантаження ...

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

Це залежить від підписів методу, у прикладі, який я дав, відсутній лише метод "int b", оскільки він матиме такий самий підпис, що і метод "int a".

Ви можете використовувати типи Nullable ...

GetFooBar (int? A, int? B)

Потім ви можете перевірити, використовуючи a.HasValue, щоб побачити, чи встановлено параметр.

Іншим варіантом буде використання параметра "params".

GetFooBar (params object [] args)

Якщо ви хочете перейти з названими параметрами, потрібно було б створити тип для їх обробки, хоча я думаю, що для веб-додатків вже є щось подібне.


24

Ви можете використовувати необов'язкові параметри в C # 4.0 без будь-яких турбот. Якщо у нас є такий метод, як:

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

коли ви викликаєте метод, ви можете пропустити такі параметри:

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

C # 4.0 реалізує функцію під назвою "названі параметри", ви можете фактично передавати параметри за їхніми іменами, і, звичайно, ви можете передавати параметри в будь-якому порядку :)


20

Привіт, необов'язковий світ

Якщо ви хочете, щоб час виконання давав значення параметра за замовчуванням, вам потрібно використовувати відображення для здійснення дзвінка. Не так приємно, як інші пропозиції щодо цього питання, але сумісні з 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

Простий спосіб, який дозволяє опускати будь-які параметри в будь-якій позиції , - це скористатись зведеними нижче типами :

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

Рядки - це вже зведені типи, тому вони не потребують ? .

Після використання цього методу всі наступні дзвінки дійсні :

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

Коли ви визначаєте метод таким чином, у вас є свобода встановлювати лише потрібні параметри, називаючи їх їх. Дивіться наступне посилання для отримання додаткової інформації про названі та необов'язкові параметри:

Іменні та необов'язкові аргументи (Посібник з програмування C #) @ MSDN


9

Я згоден зі Стефанбайєром. Але оскільки це веб-сервіс, кінцевому користувачеві легше використовувати лише одну форму веб-методу, ніж використовувати кілька версій одного методу. Я думаю, що в цій ситуації Nullable Type ідеально підходить для необов'язкових параметрів.

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 Слово поради, хоча. Не робіть це звичкою, оскільки воно може стати справді безладним.
mhenrixon

7

необов'язкові параметри призначені для методів. якщо вам потрібні необов'язкові аргументи для класу, і ви:

  • використовуючи c # 4.0: використовувати необов'язкові аргументи в конструкторі класу, я вважаю за краще рішення, оскільки це ближче до того, що робиться з методами, тому простіше запам'ятати. ось приклад:

    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 #, попередні до c # 4.0: слід використовувати ланцюжок конструкторів (використовуючи: це ключове слово), де більш прості конструктори призводять до "головного конструктора". приклад:

    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

Типовим способом, яким це обробляється в C #, як згадував Стівен, є перевантаження методу. Створюючи кілька версій методу з різними параметрами, ви ефективно створюєте необов’язкові параметри. У формах з меншою кількістю параметрів, як правило, виклик форми методу з усіма параметрами, що встановлюють значення за замовчуванням у виклику цього методу.


2

Ви можете перевантажувати свій метод. Один метод містить один параметр, GetFooBar(int a)а інший містить обидва параметри,GetFooBar(int a, int b)


2

Використання перевантажень або використання C # 4.0 або вище

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

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

1

Для більшої кількості необов'язкових параметрів за допомогою методу ContainsKey може використовуватися один параметр словника. Мені подобається такий підхід, тому що він дозволяє мені передавати список або Т окремо, без необхідності створювати зовсім інший метод (приємно, якщо параметри використовуються, наприклад, як фільтри).

Приклад (новий словник <рядок, об'єкт> () буде переданий, якщо не потрібні необов'язкові параметри):

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

0

Замість параметрів за замовчуванням, чому б просто не побудувати клас словника з переданого запиту .. реалізація, майже ідентична тому, як форми asp.net працюють з запитами.

тобто Request.QueryString ["a"]

Це від'єднає клас аркуша від коду фабрики / котла.


Ви також можете перевірити веб-служби за допомогою ASP.NET . Веб-сервіси - це веб-api, що генерується автоматично за допомогою атрибутів на класах C #.


0

Трохи запізнювався на вечірку, але я шукав відповідь на це питання і, врешті-решт, придумав ще один спосіб зробити це. Оголосіть типи даних для необов'язкових аргументів вашого веб-методу типу XmlNode. Якщо необов'язковий аргумент пропущено, це буде встановлено на нульове значення, а якщо він присутній, ви можете отримати значення рядка за допомогою виклику arg.Value, тобто,

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

Що також достойно в цьому підході - це створена .NET домашня сторінка для ws все ще показує список аргументів (хоча ви втрачаєте зручні поля введення тексту для тестування).


3
Це краще, ніж використання змінних типів?
Кірк Бродхерст

0

У мене є веб-сервіс для запису, який займає 7 параметрів. Кожен - необов'язковий атрибут запиту до заяви sql, обгорнутого цією веб-службою. Тож приходять до уваги два обхідні шляхи до необов'язкових парам ... обидва досить бідні:

метод1 (param1, param2, param 3, param 4, param 5, param 6, param7) method1 (param1, param2, param3, param 4, param5, param 6) метод 1 (param1, param2, param3, param4, param5, param7 ) ... почніть бачити картину. Таким чином криється божевілля. Шлях занадто багато комбінацій.

Тепер для більш простого способу, який виглядає незручно, але він повинен працювати: method1 (param1, bool useParam1, param2, bool useParam2 тощо)

Це один виклик методу, значення для всіх параметрів необхідні, і він буде обробляти кожен випадок всередині нього. Також зрозуміло, як ним користуватися через інтерфейс.

Це хак, але це спрацює.


2
Ось чому існують нульові параметри.
Кірк Бродхерст

0

Мені довелося це зробити у веб-службі VB.Net 2.0. Я, нарешті, вказав параметри як рядки, потім перетворив їх у все, що мені потрібно. Необов’язковий параметр був вказаний з порожнім рядком. Не найчистіше рішення, але воно спрацювало. Будьте обережні, щоб ви потрапили на всі винятки, які можуть статися.


0

На всякий випадок, якщо хтось хоче передати зворотний дзвінок (або delegate) як необов'язковий параметр, це можна зробити так.

Необов’язковий параметр зворотного виклику:

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

необов'язкові параметри - це не що інше, як параметри за замовчуванням! Я пропоную вам дати обом параметрам за замовчуванням. GetFooBar (int a = 0, int b = 0) якщо у вас немає перевантаженого методу, це призведе до a = 0, b = 0, якщо ви не передасте жодних значень, якщо ви передасте 1 значення, це призведе до , передане значення для a, 0, і якщо ви передасте 2 значення, 1-й буде призначений a, а другий b.

сподіваємось, що відповість на ваше запитання.


0

У випадку, коли значення за замовчуванням недоступні, способом додавання необов'язкового параметра є використання .NET OptionalAttribute класу - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute ? view = netframework-4.8

Приклад коду наведено нижче:

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

Ви також можете спробувати це
Тип 1
public void YourMethod(int a=0, int b = 0) { //some code }


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.