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

Note: This question was asked at a time when C# did not yet support optional parameters (i.e. before C# 4).

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

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

Или дождитесь выхода C# 4.0. Поддерживаются необязательные параметры.

Micah 18.12.2008 17:34
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
521
1
675 230
23
Перейти к ответу Данный вопрос помечен как решенный

Ответы 23

С этого сайта:

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

C# допускает использование атрибута [Optional] (из VB, но не работает в C#). Итак, у вас может быть такой метод:

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

В нашей оболочке API мы определяем необязательные параметры (ParameterInfo p.IsOptional) и устанавливаем значение по умолчанию. Цель состоит в том, чтобы пометить параметры как необязательные, не прибегая к таким кладжам, как «необязательный» в имени параметра.

Но как тогда использовать функцию Foo? Foo (1,1); foo (1,1, null) и foo (1,1, Missing.value) будут вызывать исключения

Bolu 24.09.2010 18:46

Странно, некоторые ответы выше намного лучше, чем это.

Maidot 27.06.2011 11:25

В 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
}

Я считаю, что вы не можете вызывать конструкторы в параметрах по умолчанию, они должны быть совместимы "во время компиляции", а не во "время выполнения" ... Или я ошибаюсь?

Alex 14.06.2017 13:00

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

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

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

Вы можете использовать типы, допускающие значение NULL ...

GetFooBar(int? a, int? b)

Затем вы можете проверить с помощью a.HasValue, установлен ли параметр.

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

GetFooBar(params object[] args)

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

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

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

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

DoSomething(this, that, theOther);

Этот ответ прекрасно объясняет ключевое слово params в 10 строках, MSDN по-прежнему не может сделать это в 30. +1

User2400 08.04.2010 06:46

Спасибо! Это вдохновило меня написать простую (для моего текущего варианта использования) функцию ведения журнала: 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 20.02.2015 19:09

не могли бы вы упомянуть, поддерживает ли это net 3.5? официальные документы не упомянул об этом.

T.Todua 13.02.2020 14:16

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

Tim Jarvis 17.02.2020 00:23

@TimJarvis, да, я об этом и просил. tnx

T.Todua 17.02.2020 11:32

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

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

то есть Request.QueryString ["a"]

Это отделит конечный класс от заводского / стандартного кода.


Вы также можете проверить Веб-службы с ASP.NET. Веб-службы - это веб-API, автоматически создаваемый с помощью атрибутов классов C#.

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

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 29.07.2010 11:35

Привет, необязательный мир

Если вы хотите, чтобы среда выполнения предоставляла значение параметра по умолчанию, вы должны использовать отражение для выполнения вызова. Не так хорошо, как другие предложения по этому вопросу, но совместимы с 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 });
        }
    }
}

Немного поздно на вечеринку, но я искал ответ на этот вопрос и в конце концов придумал еще один способ сделать это. Объявите типы данных для необязательных аргументов вашего веб-метода как тип XmlNode. Если необязательный аргумент опущен, для него будет установлено значение null, а если он присутствует, вы можете получить строковое значение, вызвав arg.Value, т.е.

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

Что также хорошо в этом подходе, так это то, что сгенерированная .NET домашняя страница для ws по-прежнему показывает список аргументов (хотя вы теряете удобные поля ввода текста для тестирования).

Это лучше, чем использование типов, допускающих значение NULL?

Kirk Broadhurst 25.03.2010 15:36

У меня есть веб-сервис для написания, который принимает 7 параметров. Каждый из них является необязательным атрибутом запроса для оператора sql, заключенного в эту веб-службу. Итак, на ум приходят два обходных пути для необязательных параметров ... оба довольно плохие:

метод1 (параметр1, параметр2, параметр 3, параметр 4, параметр 5, параметр 6, параметр7) метод1 (параметр1, параметр2, параметр3, параметр 4, параметр5, параметр 6) метод 1 (param1, param2, param3, param4, param5, param7) ... начать видеть картинку. В этом безумие. Слишком много комбинаций.

Теперь для более простого способа, который выглядит неудобным, но должен работать: method1 (param1, bool useParam1, param2, bool useParam2 и т. д.)

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

Это взлом, но он сработает.

Вот почему существуют параметры, допускающие значение NULL.

Kirk Broadhurst 25.03.2010 15:35
Ответ принят как подходящий

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

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

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

В то время, когда был задан вопрос, C# 4.0 не существовало.

Forrest Marvez 27.07.2010 16:54

Ага, не заметил этого, извините. Но этот вопрос по-прежнему занимает первое место в Google по "необязательным аргументам C#", так что в любом случае - этот ответ стоит здесь :)

Alex 30.07.2010 15:54

Благодарим вас за предоставление актуальной информации. В идеале исходные ответы должны быть обновлены текущей информацией, такой как C# 4.0. Я считаю, что ребята из SO изначально имели в виду менталитет Wiki, но все слишком боятся редактировать чей-то ответ.

Rowan 02.03.2011 18:26

Что-то интересное, что я обнаружил с помощью WebServices, заключается в том, что (конечно, в проекте, который я тестирую) все значения bool в строке запроса по умолчанию являются необязательными. Очевидно, они по умолчанию имеют значение FALSE.

Carlos P 29.05.2012 17:18

Но как бы вы установили объект (например, настраиваемый класс) на то, что нелегко установить по умолчанию?

James Mertz 31.07.2012 00:06

Необязательный параметр - это то же самое, что значение параметра по умолчанию?

Isaac Kleinman 08.05.2014 20:16

Можно ли это использовать с конструкторами?

Aaron Franke 08.02.2019 18:35

Стоит отметить, что необязательные параметры необходимо размещать после всех необязательных параметров. т.е. у вас не может быть public void SomeMethod (int b = 0, int a)

Andrew Meservy 27.02.2019 22:24

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

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

необязательные параметры предназначены для методов. если вам нужны необязательные аргументы для класса, и вы:

  • использование 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
        }
    }
    

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

Простой способ, позволяющий опустить любые параметры в любая позиция, заключается в использовании типы, допускающие значение NULL следующим образом:

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

Строки уже являются типами, допускающими значение NULL, поэтому им не нужен ?.

Если у вас есть этот метод, следующие вызовы будут все в силе:

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

Когда вы определяете метод таким образом, у вас есть свобода установить только те параметры, которые вы хотите, с помощью именование их. См. Следующую ссылку для получения дополнительной информации об именованных и необязательных параметрах:

Именованные и необязательные аргументы (Руководство по программированию на C#) @ MSDN

На всякий случай, если кто-то хочет передать обратный вызов (или 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;
}

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


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

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

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

Использование перегрузок или использование C# 4.0 или выше

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

 private void GetVal(string sName)
 {
    GetVal("testing", 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);
        }

    }
}

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

Пример (новый Dictionary <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;
    }
}

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

public void OptionalParameters(int requerid, int optinal = default){}

Другие вопросы по теме