簡體   English   中英

如何在 C# 中使用可選參數?

[英]How can you use optional parameters in C#?

注意:這個問題是在 C# 還不支持可選參數的時候提出的(即在 C# 4 之前)。

我們正在構建一個從 C# 類以編程方式生成的 Web API。 該類有方法GetFooBar(int a, int b) ,API 有方法GetFooBar獲取查詢參數,如&a=foo &b=bar

這些類需要支持可選參數,而 C# 語言不支持這些參數。 最好的方法是什么?

令人驚訝的是沒有人提到 C# 4.0 的可選參數是這樣工作的:

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

編輯:我知道在提出問題時,C# 4.0 不存在。 但是這個問題在“C# 可選參數”方面仍然在 Google 中排名第一,所以我認為 - 這個答案值得在這里。 對不起。

另一種選擇是使用 params 關鍵字

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

被稱為...

DoSomething(this, that, theOther);

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

從這個網站:

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) 並設置默認值。 目標是將參數標記為可選的,而不需要像在參數名稱中包含“可選”這樣的雜亂無章。

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

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)

如果您想使用命名參數,則需要創建一個類型來處理它們,盡管我認為 Web 應用程序已經有了類似的東西。

您可以毫無顧慮地在 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 實現了一個叫做“命名參數”的特性,你實際上可以通過它們的名字來傳遞參數,當然你可以按照你想要的任何順序傳遞參數:)

一種允許您在任何位置省略任何參數的簡單方法是利用可空類型,如下所示:

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

你好可選世界

如果您希望運行時提供默認參數值,則必須使用反射來進行調用。 不像這個問題的其他建議那么好,但與 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 });
        }
    }
}

我同意斯蒂芬拜爾的觀點。 但由於它是一個網絡服務,最終用戶只使用一種形式的網絡方法比使用同一方法的多個版本更容易。 我認為在這種情況下,可空類型非常適合可選參數。

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

可選參數用於方法。 如果您需要一個類的可選參數並且您是:

  • 使用 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#4.0 之前的 c# 版本:您應該使用構造函數鏈接(使用 :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 } }

正如斯蒂芬提到的那樣,在 C# 中處理這種情況的典型方法是重載該方法。 通過創建具有不同參數的方法的多個版本,您可以有效地創建可選參數。 在參數較少的表單中,您通常會調用該方法的表單,所有參數都會在調用該方法時設置默認值。

您可以重載您的方法。 一種方法包含一個參數GetFooBar(int a) ,另一種方法包含兩個參數GetFooBar(int a, int 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);
 }

對於大量可選參數,可以將Dictionary<string,Object>的單個參數與ContainsKey方法一起使用。 我喜歡這種方法,因為它允許我單獨傳遞List<T>T而無需創建整個其他方法(例如,如果將參數用作過濾器,那就太好了)。

示例(如果不需要可選參數,則將傳遞new 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;
    }
}

聚會有點晚了,但我一直在尋找這個問題的答案,並最終想出了另一種方法來做到這一點。 將 Web 方法的可選參數的數據類型聲明為 XmlNode 類型。 如果可選 arg 被省略,這將被設置為 null,如果它存在,您可以通過調用 arg.Value 來獲取字符串值,即,

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

這種方法的另一個優點是 .NET 為 ws 生成的主頁仍然顯示參數列表(盡管您確實丟失了用於測試的方便的文本輸入框)。

我有一個需要 7 個參數的 Web 服務。 每個都是此 Web 服務包裝的 sql 語句的可選查詢屬性。 所以想到了非可選參數的兩種解決方法......都非常糟糕:

方法1(參數1, 參數2, 參數3, 參數4, 參數5, 參數6, 參數7) 方法1(參數1, 參數2, 參數3, 參數4, 參數5, 參數6) 方法1(參數1, 參數2, 參數3, 參數4, 參數5, 參數7) )...開始看圖。 這種方式是瘋狂的。 組合太多了。

現在使用一種看起來很尷尬但應該工作的更簡單的方法:method1(param1, bool useParam1, param2, bool useParam2, etc...)

這是一個方法調用,所有參數的值都是必需的,它將處理其中的每種情況。 從界面上也很清楚如何使用它。

這是一個黑客,但它會起作用。

代替默認參數,為什么不從傳遞的查詢字符串構造一個字典類.. 一個實現幾乎與 asp.net 表單使用查詢字符串的方式相同。

即 Request.QueryString["a"]

這將使葉類與工廠/樣板代碼分離。


您可能還想查看使用 ASP.NET 的 Web 服務 Web 服務是通過 C# 類上的屬性自動生成的 Web api。

以防萬一,如果有人想將回調(或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;
}

我必須在 VB.Net 2.0 Web 服務中執行此操作。 我最終將參數指定為字符串,然后將它們轉換為我需要的任何內容。 使用空字符串指定了可選參數。 不是最干凈的解決方案,但它有效。 請注意捕獲所有可能發生的異常。

可選參數只不過是默認參數! 我建議你給他們兩個默認參數。 GetFooBar(int a=0, int b=0) 如果沒有任何重載方法,將導致 a=0, b=0 如果不傳遞任何值,如果傳遞 1 個值,將導致, 為 a, 0 傳遞值,如果傳遞 2 個值,第一個將分配給 a,第二個將分配給 b。

希望這能回答你的問題。

在默認值不可用的情況下,添加可選參數的方法是使用 .NET OptionalAttribute 類 - https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.optionalattribute ?view=network-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);
        }

    }
}

您可以使用默認值。

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

你也可以試試這個
類型 1
public void YourMethod(int a=0, int b = 0) { //some code }


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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM