注:この質問は、C#がオプションのパラメーターをまだサポートしていないときに(つまり、C#4の前に)尋ねられました。
プログラムでC#クラスから生成されるWeb APIを構築しています。クラスにはメソッドがGetFooBar(int a, int b)あり、APIにはのGetFooBarようなクエリパラメータを取るメソッドがあります&a=foo &b=bar。
クラスは、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で1位にランクされているので、私は思った-この答えはここにある価値がある。ごめんなさい。
別のオプションは、paramsキーワードを使用することです
public void DoSomething(params object[] theObjects)
{
foreach(object o in theObjects)
{
// Something with the Objects…
}
}
次のように呼ばれます...
DoSomething(this, that, theOther);
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");
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#では[オプション]属性を使用できます(C#では機能しませんが、VBから)。だからあなたはこのようなメソッドを持つことができます:
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 a」メソッドと同じシグネチャがあるため、「int b」のみのメソッドがありません。
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は「名前付きパラメーター」と呼ばれる機能を実装しており、実際に名前でパラメーターを渡すことができます。もちろん、パラメーターは任意の順序で渡すことができます:)
ランタイムがデフォルトのパラメーター値を提供するようにする場合は、リフレクションを使用して呼び出しを行う必要があります。この質問に対する他の提案ほど良くはありませんが、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 });
}
}
}
次のように、任意の位置でパラメータを省略できる簡単な方法は、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();
この方法でメソッドを定義すると、名前を付けて必要なパラメーターのみを自由に設定できます。名前付きパラメータとオプションパラメータの詳細については、次のリンクを参照してください。
私はスティーブンバイヤーに同意します。ただし、これは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
}
}
オプションのパラメーターはメソッド用です。クラスにオプションの引数が必要な場合:
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
}
}メソッドをオーバーロードできます。1つのメソッドには1つのパラメーターが含まれGetFooBar(int a)、もう1つのメソッドには両方のパラメーターが含まれます。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);
}
オプションパラメータの数が多い場合は、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;
}
}
デフォルトのパラメータの代わりに、渡されたクエリ文字列からディクショナリクラスを作成するだけではなく、asp.netフォームがクエリ文字列を処理する方法とほぼ同じ実装です。
ie Request.QueryString ["a"]
これにより、リーフクラスがファクトリー/ボイラープレートコードから分離されます。
ASP.NETでWebサービスをチェックアウトすることもできます。Webサービスは、C#クラスの属性を介して自動的に生成されるWeb APIです。
パーティーには少し遅れましたが、私はこの質問に対する答えを探していて、最終的にこれを行う別の方法を見つけました。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ステートメントに対するオプションのクエリ属性です。したがって、オプションではないパラメータに対する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つのメソッド呼び出しであり、すべてのパラメーターの値が必要であり、その中の各ケースを処理します。インターフェースからの使い方も明らかです。
これはハックですが、機能します。
誰かが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;
}
オプションのパラメーターは、デフォルトのパラメーターにすぎません!両方にデフォルトのパラメータを指定することをお勧めします。GetFooBar(int a = 0、int b = 0)オーバーロードされたメソッドがない場合は、a = 0、b = 0は値を渡さない場合、1つの値を渡した場合は、aに渡された値、0、2つの値を渡した場合、1番目はaに、2番目はbに割り当てられます。
それがあなたの質問に答えることを願っています。
デフォルト値が使用できない場合、オプションのパラメーターを追加する方法は、.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);
}
}
}
あなたもこれを試すことができます
タイプ1
public void YourMethod(int a=0, int b = 0)
{
//some code
}
タイプ2
public void YourMethod(int? a, int? b)
{
//some code
}