Как вы можете использовать дополнительные параметры в C #?

493

Примечание. Этот вопрос задавался в то время, когда C # еще не поддерживал необязательные параметры (т. Е. До C # 4).

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

Классы должны поддерживать необязательные параметры, которые не поддерживаются в языке C #. Какой лучший подход?

Kalid
источник
7
Или подожди пока унитил C # 4.0. Необязательные параметры поддерживаются.
Михей

Ответы:

1055

Удивил никто не упомянул C # 4.0 необязательные параметры, которые работают так:

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

Редактировать: я знаю, что в то время, когда был задан вопрос, C # 4.0 не существовало. Но этот вопрос по-прежнему занимает № 1 в Google за «необязательные аргументы C #», поэтому я подумал - этот ответ стоит того, чтобы быть здесь. Сожалею.

Alex
источник
58
В то время, когда был задан вопрос, C # 4.0 не существовало.
Форрест Марвез
91
Да, пропустил это, извините. Но этот вопрос по-прежнему занимает № 1 в Google за «необязательные аргументы C #», так что в любом случае - этот ответ стоит быть здесь :)
Алекс
45
Хорошо, что вы предоставили актуальную информацию. В идеале оригинальные ответы должны быть обновлены текущей информацией, такой как C # 4.0. Я верю, что именно это изначально и думали парни из SO, вики-менталитет, но все слишком боятся редактировать чужой ответ.
Роуэн
Что-то интересное, что я обнаружил с помощью WebServices, заключается в том, что (безусловно, в тестируемом проекте) все значения bool в строке запроса являются необязательными по умолчанию. Очевидно, они по умолчанию ЛОЖЬ.
Карлос П
4
Стоит отметить, что необязательные параметры должны быть размещены после всех необязательных параметров. т.е. у вас не может быть публичного void SomeMethod (int b = 0, int a)
Эндрю Месерви
129

Другой вариант - использовать ключевое слово params.

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

Называется как ...

DoSomething(this, that, theOther);
Тим Джарвис
источник
57
Этот ответ объясняет ключевое слово params beautifilly в 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");
варианта
не могли бы вы упомянуть, поддерживает ли net 3.5? официальные документы не упоминали об этом.
Т.Тодуа
@ T.Todua - я не уверен на 100%, что вы спрашиваете здесь - dotnet framework 3.5 включала C # v3.0 - версия 3.0 действительно поддерживала ключевое слово params, но не имела необязательных параметров, которые были введены в C # v4.0 , которая была включена в dotnet framework 4.0
Тим Джарвис
@TimJarvis Да, это то, о чем я просил. tnx
T.Todua
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
}
stephenbayer
источник
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.IsOptional) и устанавливаем значение по умолчанию. Цель состоит в том, чтобы пометить параметры как необязательные, не прибегая к кладбищам, таким как наличие «необязательного» в имени параметра.

Kalid
источник
4
Но как использовать функцию Foo тогда? Foo (1,1); foo (1,1, null) и foo (1,1, Missing.value) будут выбрасывать исключения
Болу
2
Странно, некоторые ответы выше намного лучше, чем это.
Майдот
26

Вы можете использовать метод перегрузки ...

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

Это зависит от сигнатур метода, в приведенном мною примере отсутствует метод «только b», поскольку он будет иметь такую ​​же сигнатуру, что и метод «int a».

Вы можете использовать Nullable типы ...

GetFooBar (int? A, int? B)

Затем вы можете проверить, используя a.HasValue, чтобы увидеть, был ли установлен параметр.

Другой вариант - использовать параметр «params».

GetFooBar (params object [] args)

Если бы вы хотели использовать именованные параметры, нужно было бы создать тип для их обработки, хотя я думаю, что для веб-приложений уже есть нечто подобное.

Kepboy
источник
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 реализована функция, называемая «именованные параметры», вы можете передавать параметры по их именам, и, конечно, вы можете передавать параметры в любом порядке :)

kristi_io
источник
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

SteakOverflow
источник
9

Я согласен со Стивенбайером. Но поскольку это веб-сервис, конечному пользователю проще использовать только одну форму веб-метода, чем использовать несколько версий одного и того же метода. Я думаю, что в этой ситуации Nullable Types идеально подходят для необязательных параметров.

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: вы должны использовать цепочку конструктора (используя ключевое слово: this), где более простые конструкторы приводят к «главному конструктору». пример:

    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
        }
    }
baskinhu
источник
3

Типичный способ, которым это обрабатывается в C #, как упомянул Стивен, - перегрузить метод. Создавая несколько версий метода с различными параметрами, вы эффективно создаете необязательные параметры. В формах с меньшим количеством параметров вы обычно вызываете форму метода со всеми параметрами, устанавливающими значения по умолчанию при вызове этого метода.

cfbarbero
источник
2

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

user2933082
источник
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

Для большего количества необязательных параметров можно использовать один параметр Dictionary с методом ContainsKey. Мне нравится этот подход, потому что он позволяет мне передавать List или T по отдельности, не создавая совершенно другой метод (хорошо, если, например, параметры должны использоваться в качестве фильтров).

Пример (новый словарь <string, Object> () будет передан, если не требуются дополнительные параметры):

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 опущен, для него будет установлено значение null, а если он присутствует, вы можете получить строковое значение, вызвав 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, заключенного в этот веб-сервис. Итак, на ум приходят два обходных пути к необязательным параметрам ... оба довольно плохие:

method1 (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 и т. Д ...)

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

Это взлом, но это будет работать.

Spanky
источник
2
Вот почему существуют обнуляемые параметры.
Кирк Бродхерст
0

Я должен был сделать это в веб-сервисе VB.Net 2.0. В итоге я указал параметры в виде строк, а затем преобразовал их в то, что мне было нужно. Необязательный параметр был указан с пустой строкой. Не самое чистое решение, но оно сработало. Просто будьте осторожны, чтобы вы поймали все исключения, которые могут произойти.

Matt
источник
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;
}
CodeArtist
источник
0

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

Надеюсь это ответит на твой вопрос.

user3555836
источник
0

Если значения по умолчанию недоступны, можно добавить необязательный параметр, используя класс .NET OptionalAttribute - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute. ? вид = 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 }

Анкит Панвар
источник