C#でオプションのパラメーターをどのように使用できますか?


493

注:この質問は、C#がオプションのパラメーターをまだサポートしていないときに(つまり、C#4の前に)尋ねられました。

プログラムでC#クラスから生成されるWeb APIを構築しています。クラスにはメソッドがGetFooBar(int a, int b)あり、APIにはのGetFooBarようなクエリパラメータを取るメソッドがあります&a=foo &b=bar

クラスは、C#言語でサポートされていないオプションのパラメーターをサポートする必要があります。最善のアプローチは何ですか?


7
またはunitil C#4.0がリリースされるのを待ちます。オプションのパラメータがサポートされています。
ミカ

回答:


1055

次のように機能するC#4.0のオプションパラメータについて誰も言及していません。

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

編集:質問があったときに、C#4.0が存在しなかったことを知っています。しかし、この質問はまだ「C#オプション引数」でGoogleで1位にランクされているので、私は思った-この答えはここにある価値がある。ごめんなさい。


58
質問された時点では、C#4.0は存在しませんでした。
フォレストマルベス

91
うん、見落としました、すみません。しかし、この質問はまだ「C#オプション引数」でGoogleで1位にランク付けされているので、とにかく-この答えはここにある価値があります:)
Alex

45
最新の情報を提供してくれてありがとう。理想的には、元の回答はC#4.0などの最新情報で更新されます。私はそもそもSOの人たちがWikiの考え方を考えていたと思いますが、誰もが他の人の答えを編集するのは少し怖いです。
Rowan

WebServicesで私が発見した興味深いことの1つは(確かに私がテストしているプロジェクトでは)、クエリ文字列のすべてのbool値はデフォルトでオプションです。明らかにデフォルトはFALSEです。
Carlos P

4
オプションパラメータは、すべての非オプションパラメータの後に配置する必要があることに注意してください。つまり、public void 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
この回答は、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");
pfonseca '20

net 3.5はそれをサポートしていますか?公式ドキュメントはそれについて言及していません。
T.Todua

@ T.Todua-ここで何を求めているのか100%わかりません-dotnet framework 3.5にはC#v3.0が含まれていました-バージョン3.0ではparamsキーワードがサポートされていましたが、C#v4.0で導入されたオプションのパラメーターはありませんでした、dotnetフレームワーク4.0に含まれていた
Tim Jarvis

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

1
私はあなたがデフォルトのパラメータでコンストラクタを呼び出すことができないと信じています、それらは「ランタイム」ではなく「コンパイル時」互換である必要があります...または私は間違っていますか?
Alex

45

このサイトから:

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

C#では[オプション]属性を使用できます(C#では機能しませんが、VBから)。だからあなたはこのようなメソッドを持つことができます:

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

APIラッパーで、オプションのパラメーター(ParameterInfo p.IsOptional)を検出し、デフォルト値を設定します。目標は、パラメーター名に「オプション」があるようなクラッジに頼らずにパラメーターをオプションとしてマークすることです。


4
しかし、関数Fooの使い方は?Foo(1,1); foo(1,1、null)およびfoo(1,1、Missing.value)はすべて例外をスローします
Bolu

2
奇妙なことに、上記のいくつかの答えはこれよりもはるかに優れています。
Maidot

26

メソッドのオーバーロードを使用できます...

GetFooBar()
GetFooBar(int a)
GetFooBar(int a、int b)

これはメソッドのシグネチャに依存します。私が示した例には、「int a」メソッドと同じシグネチャがあるため、「int b」のみのメソッドがありません。

Nullable型を使用できます...

GetFooBar(int?a、int?b)

次に、a.HasValueを使用して、パラメーターが設定されているかどうかを確認できます。

別のオプションは、「params」パラメータを使用することです。

GetFooBar(params object [] args)

名前付きパラメーターを使用する場合は、それらを処理するタイプを作成する必要がありますが、Webアプリにはすでにこのようなものがあると思います。


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

次のように、任意の位置パラメータを省略できる簡単な方法は、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


9

私はスティーブンバイヤーに同意します。ただし、これはWebサービスであるため、同じメソッドの複数のバージョンを使用するよりも、エンドユーザーが1つの形式の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
  }  
}

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

3

スティーブンが述べたようにこれがC#で処理される典型的な方法は、メソッドをオーバーロードすることです。異なるパラメーターでメソッドの複数のバージョンを作成することにより、オプションのパラメーターを効果的に作成できます。パラメータの少ないフォームでは、通常、メソッドの呼び出しでデフォルト値を設定するすべてのパラメータを使用してメソッドのフォームを呼び出します。


2

メソッドをオーバーロードできます。1つのメソッドには1つのパラメーターが含まれGetFooBar(int a)、もう1つのメソッドには両方のパラメーターが含まれます。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

オプションパラメータの数が多い場合は、ContainersKeyメソッドでDictionaryの単一のパラメータを使用できます。他のメソッド全体を作成せずにリストまたは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;
    }
}

0

デフォルトのパラメータの代わりに、渡されたクエリ文字列からディクショナリクラスを作成するだけではなく、asp.netフォームがクエリ文字列を処理する方法とほぼ同じ実装です。

ie Request.QueryString ["a"]

これにより、リーフクラスがファクトリー/ボイラープレートコードから分離されます。


ASP.NETでWebサービスをチェックアウトすることもできます。Webサービスは、C#クラスの属性を介して自動的に生成されるWeb APIです。


0

パーティーには少し遅れましたが、私はこの質問に対する答えを探していて、最終的にこれを行う別の方法を見つけました。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のホームページにも引数リストが表示されることです(ただし、テスト用の便利なテキスト入力ボックスはありません)。


3
これはnull許容型を使用するよりも優れていますか?
カークブロードハースト

0

私は、7つのパラメーターをとるWebサービスを作成しています。それぞれは、このWebサービスによってラップされたSQLステートメントに対するオプションのクエリ属性です。したがって、オプションではないパラメータに対する2つの回避策が思い浮かびます...どちらもかなり貧弱です:

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 )...写真を見始めます。この方法は狂気です。組み合わせが多すぎます。

見栄えが悪いが動作するはずの簡単な方法:method1(param1、bool useParam1、param2、bool useParam2など...)

これは1つのメソッド呼び出しであり、すべてのパラメーターの値が必要であり、その中の各ケースを処理します。インターフェースからの使い方も明らかです。

これはハックですが、機能します。


2
これが、null許容パラメータが存在する理由です。
カークブロードハースト

0

VB.Net 2.0 Webサービスでこれを行う必要がありました。パラメータを文字列として指定し、必要なものに変換しました。オプションのパラメーターが空の文字列で指定されました。最もクリーンなソリューションではありませんが、うまくいきました。発生する可能性のあるすべての例外をキャッチするように注意してください。


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に、2番目は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 }

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.