如何在 C# 中使用可选参数?

发布于 2024-07-07 18:42:40 字数 288 浏览 9 评论 0原文

注意:这个问题是在 C# 尚不支持可选参数时(即 C# 4 之前)提出的。

我们正在构建一个 Web API,它是通过编程方式从C# 类。 该类有方法 GetFooBar(int a, int b) 并且 API 有一个方法 GetFooBar 接受查询参数,如 &a=foo &b=bar

这些类需要支持可选参数,而 C# 语言不支持该参数。 最好的方法是什么?

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

We're building a web API that's programmatically generated from a C# class. The class has method GetFooBar(int a, int b) and the API has a method GetFooBar taking query params like &a=foo &b=bar.

The classes needs to support optional parameters, which isn't supported in C# the language. What's the best approach?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

倒数 2024-07-14 18:42:41

正如斯蒂芬提到的,在 C# 中处理此问题的典型方法是重载该方法。 通过使用不同参数创建方法的多个版本,您可以有效地创建可选参数。 在参数较少的表单中,您通常会调用方法的表单,其中所有参数都在调用该方法时设置默认值。

The typical way this is handled in C# as stephen mentioned is to overload the method. By creating multiple versions of the method with different parameters you effectively create optional parameters. In the forms with fewer parameters you would typically call the form of the method with all of the parameters setting your default values in the call to that method.

左秋 2024-07-14 18:42:41

使用重载或使用 C# 4.0 或更高版本

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

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

Using overloads or using C# 4.0 or above

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

 private void GetVal(string sName)
 {
    GetVal("testing", 0);
 }
与之呼应 2024-07-14 18:42:41

您可以重载您的方法。 一种方法包含一个参数 GetFooBar(int a),另一种方法包含两个参数 GetFooBar(int a, int b)

You can overload your method. One method contains one parameter GetFooBar(int a) and the other contain both parameters, GetFooBar(int a, int b)

因为看清所以看轻 2024-07-14 18:42:41

您可以使用默认值。

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

You can use default.

public void OptionalParameters(int requerid, int optinal = default){}
内心旳酸楚 2024-07-14 18:42:41

对于大量可选参数,Dictionary 的单个参数可以与 ContainsKey 方法一起使用。 我喜欢这种方法,因为它允许我单独传递 ListT ,而无需创建整个其他方法(如果将参数用作例如过滤器)。

示例(如果不需要可选参数,则将传递new Dictionary()):

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

For a larger number of optional parameters, a single parameter of Dictionary<string,Object> could be used with the ContainsKey method. I like this approach because it allows me to pass a List<T> or a T individually without having to create a whole other method (nice if parameters are to be used as filters, for example).

Example (new Dictionary<string,Object>() would be passed if no optional parameters are desired):

public bool Method(string ParamA, Dictionary<string,Object> AddlParams) {
    if(ParamA == "Alpha" && (AddlParams.ContainsKey("foo") || AddlParams.ContainsKey("bar"))) {
        return true;
    } else {
        return false;
    }
}
吃兔兔 2024-07-14 18:42:41

为什么不直接从传递的查询字符串构造一个字典类,而不是默认参数......一个与 ASP.NET 表单使用查询字符串的方式几乎相同的实现。

即 Request.QueryString["a"]

这会将叶类与工厂/样板代码分离。


您可能还想查看使用 ASP.NET 的 Web 服务。 Web 服务是通过 C# 类的属性自动生成的 Web API。

Instead of default parameters, why not just construct a dictionary class from the querystring passed .. an implementation that is almost identical to the way asp.net forms work with querystrings.

i.e. Request.QueryString["a"]

This will decouple the leaf class from the factory / boilerplate code.


You also might want to check out Web Services with ASP.NET. Web services are a web api generated automatically via attributes on C# classes.

人│生佛魔见 2024-07-14 18:42:41

聚会有点晚了,但我一直在寻找这个问题的答案,并最终找到了另一种方法来做到这一点。 将 Web 方法的可选参数的数据类型声明为 XmlNode 类型。 如果省略可选参数,则该参数将设置为 null,如果存在,您可以通过调用 arg.Value 获取字符串值,即,

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

此方法的另一个不错之处是 .NET 为 ws 生成的主页仍然显示参数列表(尽管您确实失去了用于测试的方便的文本输入框)。

A little late to the party, but I was looking for the answer to this question and ultimately figured out yet another way to do this. Declare the data types for the optional args of your web method to be type XmlNode. If the optional arg is omitted this will be set to null, and if it's present you can get is string value by calling arg.Value, i.e.,

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

What's also decent about this approach is the .NET generated home page for the ws still shows the argument list (though you do lose the handy text entry boxes for testing).

£冰雨忧蓝° 2024-07-14 18:42:41

我要编写一个需要 7 个参数的 Web 服务。 每个都是此 Web 服务包装的 SQL 语句的可选查询属性。 因此,我想到了非可选参数的两种解决方法......都非常糟糕:

method1(param1, param2, param 3, param 4, param 5, param 6, param7)
方法1(参数1,参数2,参数3,参数4,参数5,参数6)
方法1(param1,param2,param3,param4,param5,param7)...开始看图。 这条路就是疯狂。 组合太多了。

现在有一种看起来很尴尬但应该可行的更简单的方法:
method1(param1, bool useParam1, param2, bool useParam2, etc...)

这是一个方法调用,所有参数的值都是必需的,它将处理其中的每种情况。 如何从界面中使用它也很清楚。

这是一个 hack,但它会起作用。

I have a web service to write that takes 7 parameters. Each is an optional query attribute to a sql statement wrapped by this web service. So two workarounds to non-optional params come to mind... both pretty poor:

method1(param1, param2, param 3, param 4, param 5, param 6, param7)
method1(param1, param2, param3, param 4, param5, param 6)
method 1(param1, param2, param3, param4, param5, param7)... start to see the picture. This way lies madness. Way too many combinations.

Now for a simpler way that looks awkward but should work:
method1(param1, bool useParam1, param2, bool useParam2, etc...)

That's one method call, values for all parameters are required, and it will handle each case inside it. It's also clear how to use it from the interface.

It's a hack, but it will work.

清引 2024-07-14 18:42:41

我必须在 VB.Net 2.0 Web 服务中执行此操作。 我最终将参数指定为字符串,然后将它们转换为我需要的任何内容。 使用空字符串指定了可选参数。 这不是最干净的解决方案,但它确实有效。 请注意捕获所有可能发生的异常。

I had to do this in a VB.Net 2.0 Web Service. I ended up specifying the parameters as strings, then converting them to whatever I needed. An optional parameter was specified with an empty string. Not the cleanest solution, but it worked. Just be careful that you catch all the exceptions that can occur.

无风消散 2024-07-14 18:42:41

为了以防万一,如果有人想将回调(或委托)作为可选参数传递,可以这样做。

可选回调参数:

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

For just in case if someone wants to pass a callback (or delegate) as an optional parameter, can do it this way.

Optional Callback parameter:

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;
}
恰似旧人归 2024-07-14 18:42:41

可选参数只不过是默认参数!
我建议你给它们两个默认参数。
GetFooBar(int a=0, int b=0) 如果没有任何重载方法,将导致 a=0,如果不传递任何值,将导致 b=0,如果传递 1 值,将导致,传递 a 值,0,如果传递 2 个值,第一个值将分配给 a,第二个值分配给 b。

希望这能回答你的问题。

optional parameters are nothing but default parameters!
i suggest you give both of them default parameters.
GetFooBar(int a=0, int b=0) if you don't have any overloaded method, will result in a=0, b=0 if you don't pass any values,if you pass 1 value, will result in, passed value for a, 0 and if you pass 2 values 1st will be assigned to a and second to b.

hope that answers your question.

方觉久 2024-07-14 18:42:41

如果默认值不可用,添加可选参数的方法是使用 .NETOptionalAttribute 类 - https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.opticalattribute?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);
        }

    }
}

In the case when default values aren't available the way to add an optional parameter is to use .NET OptionalAttribute class - https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute?view=netframework-4.8

Example of the code is below:

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

    }
}
新雨望断虹 2024-07-14 18:42:41

你也可以试试这个
类型 1
public void YourMethod(int a=0, int b = 0)
{
//一些代码
}

类型 2
public void YourMethod(int?a, int?b)
{
//一些代码
}

You can try this too
Type 1
public void YourMethod(int a=0, int b = 0)
{
//some code
}

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

╰◇生如夏花灿烂 2024-07-14 18:42:40

在 C# 4.0 中,您可以使用可选参数,其工作方式如下:

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

With C# 4.0 you can use optional parameters that work like this:

public void SomeMethod(int a, int b = 0)
{
   //some code
}
绝影如岚 2024-07-14 18:42:40

另一种选择是使用 params 关键字

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

Called like...

DoSomething(this, that, theOther);

Another option is to use the params keyword

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

Called like...

DoSomething(this, that, theOther);
微暖i 2024-07-14 18:42:40

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

In C#, I would normally use multiple forms of the method:

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

UPDATE: This mentioned above WAS the way that I did default values with C# 2.0. The projects I'm working on now are using C# 4.0 which now directly supports optional parameters. Here is an example I just used in my own code:

public EDIDocument ApplyEDIEnvelop(EDIVanInfo sender, 
                                   EDIVanInfo receiver, 
                                   EDIDocumentInfo info,
                                   EDIDocumentType type 
                                     = new EDIDocumentType(EDIDocTypes.X12_814),
                                   bool Production = false)
{
   // My code is here
}
若有似无的小暗淡 2024-07-14 18:42:40

从该网站:

https://www.tek-tips.com/viewthread.cfm ?qid=1500861

C# 允许使用 [Optional] 属性(来自 VB,但在 C# 中不起作用)。 所以你可以有这样的方法:

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

在我们的 API 包装器中,我们检测可选参数 (ParameterInfo p.IsOptional) 并设置默认值。 目标是将参数标记为可选,而不需要像在参数名称中包含“可选”这样的拼凑。

From this site:

https://www.tek-tips.com/viewthread.cfm?qid=1500861

C# does allow the use of the [Optional] attribute (from VB, though not functional in C#). So you can have a method like this:

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

In our API wrapper, we detect optional parameters (ParameterInfo p.IsOptional) and set a default value. The goal is to mark parameters as optional without resorting to kludges like having "optional" in the parameter name.

花海 2024-07-14 18:42:40

您可以使用方法重载...

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)

如果你想使用命名参数,则需要创建一个类型来处理它们,尽管我认为网络应用程序已经有了类似的东西。

You could use method overloading...

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

It depends on the method signatures, the example I gave is missing the "int b" only method because it would have the same signature as the "int a" method.

You could use Nullable types...

GetFooBar(int? a, int? b)

You could then check, using a.HasValue, to see if a parameter has been set.

Another option would be to use a 'params' parameter.

GetFooBar(params object[] args)

If you wanted to go with named parameters would would need to create a type to handle them, although I think there is already something like this for web apps.

ㄟ。诗瑗 2024-07-14 18:42:40

您可以在 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实现了一个称为“命名参数”的功能,你实际上可以通过参数的名称来传递参数,当然你可以按任何顺序传递参数你要 :)

You can use optional parameters in C# 4.0 without any worries.
If we have a method like:

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

when you call the method, you can skip parameters like this:

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

C# 4.0 implements a feature called "named parameters", you can actually pass parameters by their names, and of course you can pass parameters in whatever order you want :)

怎言笑 2024-07-14 18:42:40

允许您在任何位置省略任何参数的一种简单方法是利用可为空类型,如下所示:

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

当您以这种方式定义方法时,您可以通过命名自由地设置您想要的参数。

这种定义方法的方式虽然增加了额外的检查、更多的代码行,并允许编写令人眼花缭乱的方法调用,即 PrintValues(null, 2, s:"ciao", c:null);,所以我认为这种风格应该偶尔使用。

有关命名参数和可选参数的更多信息,请访问以下链接:

命名参数和可选参数 (C#编程指南)@MSDN

An easy way that allows you to omit any parameters in any position, is taking advantage of nullable types as follows:

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

Strings are already nullable types so they don't need the ?.

Once you have this method, the following calls are all valid:

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

When you define a method that way, you have the freedom to set just the parameters you want by naming them.

This way of defining methods though adds additional checks, more lines of code and allows writing method calls that are heavy to the eye, i.e. PrintValues(null, 2, s:"ciao", c:null);, so this style should be used sporadically in my opinion.

More information on named and optional parameters at the following link:

Named and Optional Arguments (C# Programming Guide) @ MSDN

请恋爱 2024-07-14 18:42:40

HelloOptionalWorld

如果您希望运行时提供默认参数值,则必须使用反射来进行调用。 不像这个问题的其他建议那么好,但与 VB.NET 兼容。

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

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

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

Hello Optional World

If you want the runtime to supply a default parameter value, you have to use reflection to make the call. Not as nice as the other suggestions for this question, but compatible with VB.NET.

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

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

       [STAThread]
       public static void Main(string[] args)
       {
            MethodInfo mi = typeof(Class1).GetMethod("sayHelloTo");
            mi.Invoke(null, new Object[] { Missing.Value });
       }
    }
}
凯凯我们等你回来 2024-07-14 18:42:40

我同意斯蒂芬拜尔的观点。 但由于它是一项 Web 服务,因此最终用户仅使用一种形式的 Web 方法比使用同一方法的多个版本更容易。 我认为在这种情况下,可空类型非常适合可选参数。

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

I agree with stephenbayer. But since it is a webservice, it is easier for end-user to use just one form of the webmethod, than using multiple versions of the same method. I think in this situation Nullable Types are perfect for optional parameters.

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
  }  
}
青巷忧颜 2024-07-14 18:42:40

可选参数用于方法。 如果您需要类的可选参数,并且您是:

  • 使用 c# 4.0:在类的构造函数中使用可选参数,这是我更喜欢的解决方案,因为它更接近于方法,因此更容易记住。 这是一个例子:

    类 myClass 
      { 
          公共 myClass(int myInt = 1, 字符串 myString = 
                                 “哇,这太酷了:我可以有一个默认字符串”) 
          { 
              // 如果需要的话在这里做一些事情 
          } 
      } 
      
  • 使用 c#4.0 之前的 c# 版本:您应该使用构造函数链(使用 :this 关键字),其中更简单的构造函数会生成“主构造函数”。
    示例:

    类 myClass 
      { 
          公共我的类() 
          { 
          // 这是默认的构造函数 
          } 
    
          公共 myClass(int myInt) 
              :这个(myInt,“无论如何”) 
          { 
              // 如果需要的话在这里做一些事情 
          } 
          公共 myClass(字符串 myString) 
              :这个(0,myString) 
          { 
              // 如果需要的话在这里做一些事情 
          } 
          公共 myClass(int myInt, 字符串 myString) 
          { 
              // 如果需要的话在这里做一些事情 - 这是主构造函数 
          } 
      } 
      

optional parameters are for methods. if you need optional arguments for a class and you are:

  • using c# 4.0: use optional arguments in the constructor of the class, a solution i prefer, since it's closer to what is done with methods, so easier to remember. here's an example:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
    
  • using c# versions previous to c#4.0: you should use constructor chaining (using the :this keyword), where simpler constructors lead to a "master constructor".
    example:

    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
        }
    }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文