注: この質問は、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の#1にランクされているので、私は思った - この答えはここにある価値がある。ごめんなさい。
もう1つの選択肢は、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)を検出し、デフォルト値を設定します。目的は、パラメータ名に "optional"を含めるなどの簡単な操作をせずに、パラメータをオプションとしてマークすることです。
あなたはメソッドオーバーロードを使用することができます...
GetFooBar() GetFooBar(int a) GetFooBar(int a、int b)
それはメソッドシグネチャに依存します、私が与えた例はそれが "int a"メソッドと同じシグネチャを持つことになるので "int b"だけのメソッドが欠けています。
あなたはnull許容型を使用することができます...
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は「名前付きパラメータ」と呼ばれる機能を実装しています。実際には名前でパラメータを渡すことができます。もちろん、好きな順序でパラメータを渡すこともできます。
ランタイムにデフォルトのパラメータ値を提供したい場合は、リフレクションを使用して呼び出しを行う必要があります。この質問に対する他の提案ほど素敵ではありませんが、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 });
}
}
}
任意のパラメータ in 任意の位置 を省略できる簡単な方法は、次のように 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();
そのようにメソッドを定義するときには、 ネーミング それらによってあなたが望むパラメータだけを設定する自由があります。名前付きパラメータとオプションパラメータの詳細については、次のリンクを参照してください。
私はstephenbayerに同意します。しかし、これはWebサービスであるため、エンドユーザーが同じ方法の複数のバージョンを使用するよりも、1つの形式のWebメソッドを使用する方が簡単です。このような状況では、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
}
}
オプションのパラメータはメソッド用です。クラスにオプションの引数が必要で、かつあなたが
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
}
}
Stephenが述べたようにこれがC#で処理される典型的な方法はメソッドをオーバーロードすることです。異なるパラメータを使用してメソッドの複数のバージョンを作成することで、オプションのパラメータを効果的に作成できます。パラメータが少ないフォームでは、通常、そのメソッドの呼び出しでデフォルト値を設定するすべてのパラメータを使用してメソッドのフォームを呼び出します。
あなたはあなたの方法をオーバーロードすることができます。 1つのメソッドは1つのパラメータGetFooBar(int a)
を含み、もう1つのメソッドは両方のパラメータGetFooBar(int a, int b)
を含みます
デフォルトのパラメータの代わりに、渡されたクエリ文字列から辞書クラスを構築しないようにしましょう。
すなわちRequest.QueryString ["a"]
これにより、リーフクラスがファクトリ/ボイラープレートコードから切り離されます。
また、 ASP.NETによるWebサービスをチェックアウトすることもできます 。 Webサービスは、C#クラスの属性を介して自動的に生成されるWeb APIです。
オプションのパラメータはデフォルトのパラメータに他なりません。両方ともデフォルトのパラメータを指定することをお勧めします。オーバーロードされたメソッドがない場合はGetFooBar(int a = 0、int b = 0)はa = 0になり、値を渡さないとb = 0になります。1の値を渡すとaに渡された値は、0で、2つの値を渡した場合は、1stがaに割り当てられ、2ndがbに割り当てられます。
それがあなたの質問に答えることを願っています。
パーティーには少し遅れましたが、私はこの質問に対する答えを探していて、最終的にこれを行うためのさらに別の方法を考え出しました。 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用のホームページにはまだ引数リストが表示されることです(ただし、テスト用の便利なテキスト入力ボックスはなくなります)。
念のために、誰かがオプションのパラメータとしてコールバック(または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サービスでこれをしなければなりませんでした。パラメータを文字列として指定してから、必要なものに変換しました。オプションのパラメーターが空ストリングで指定されました。最もきれいな解決策ではないが、それはうまくいった。発生する可能性があるすべての例外をキャッチするように注意してください。
私は7つのパラメータをとるWebサービスを書くことができます。それぞれが、このWebサービスによってラップされたSQLステートメントに対するオプションのquery属性です。そのため、オプションではないパラメータに対する2つの回避策が思い浮かぶでしょう。どちらもかなり貧弱です。
method 1(param 1、param 2、param 3、param 4、param 5、param 6、param 7)method 1(param 1、param 2、param 3、param 4、param 5、param 6)method 1(param 1、param 2、param 3、param 4、param 5、param 7) ……絵を見始めます。このように狂気があります。あまりにも多くの組み合わせ。
ぎこちなく見えますが、動作するはずの、より単純な方法です。method1(param1、bool useParam1、param2、bool useParam2など)
これは1回のメソッド呼び出しで、すべてのパラメータの値が必要です。内部の各ケースを処理します。インターフェースからそれを使用する方法も明らかです。
これはハックですが、うまくいくでしょう。