配列を分解して、その要素をparamsキーワードでメソッドに渡すことができますか?
-
08-07-2019 - |
質問
この非コンパイルコードを例にとります:
public string GetPath(string basefolder, string[] extraFolders)
{
string version = Versioner.GetBuildAndDotNetVersions();
string callingModule = StackCrawler.GetCallingModuleName();
return AppendFolders(basefolder, version, callingModule, extraFolders);
}
private string AppendFolders(params string[] folders)
{
string outstring = folders[0];
for (int i = 1; i < folders.Length; i++)
{
string fixedPath = folders[i][0] == '\\' ? folders[i].Substring(1) : folders[i];
Path.Combine(outstring, fixedPath);
}
return outstring;
}
この例は、使用しているテストコードのやや簡略化されたバージョンです。 paramキーワードと直接関係するソリューションにのみ興味があります。リストやその他の類似したものがどのように機能するか知っています。
<!> quot; explode <!> quot;への方法はありますか? extraFolders配列を使用して、その内容を他のパラメーターとともにAppendFoldersに渡すことができますか?
解決
1つのオプションは、params
パラメーターをobject[]
:
static string appendFolders(params object[] folders)
{ return (string) folders.Aggregate("",(output, f) =>
Path.Combine( (string)output
,(f is string[])
? appendFolders((object[])f)
: ((string)f).TrimStart('\\')));
}
より厳密に型指定されたものが必要な場合は、暗黙の変換演算子を使用してカスタムのユニオン型を作成することもできます。
static string appendFolders(params StringOrArray[] folders)
{ return folders.SelectMany(x=>x.AsEnumerable())
.Aggregate("",
(output, f)=>Path.Combine(output,f.TrimStart('\\')));
}
class StringOrArray
{ string[] array;
public IEnumerable<string> AsEnumerable()
{ return soa.array;}
public static implicit operator StringOrArray(string s)
{ return new StringOrArray{array=new[]{s}};}
public static implicit operator StringOrArray(string[] s)
{ return new StringOrArray{array=s};}
}
どちらの場合でも、これはコンパイルします:
appendFolders("base", "v1", "module", new[]{"debug","bin"});
他のヒント
そのまま渡します。 folderパラメーターは最初の配列です。 <!> quot; params <!> quot;機能はコンパイラのちょっとした魔法ですが、必須ではありません。
AppendFolders(extraFolders);
今、この特定のインスタンスです。まず、その配列にいくつかのものを追加する必要があります。
List<string> lstFolders = new List<string>(extraFolders);
lstFolder.Insert(0, callingModule);
lstFolder.Insert(0, version);
lstFolder.Insert(0, basefolder);
return AppendFolders(lstFolders.ToArray());
<!> quot; expand <!> quot;が本当に必要だと思われるので、<!> quot; collapse <!> quot;という用語と口論します。そして、私はあなたがソリューションで何を意味するのかわかりません<!> quot;直接params keyword <!> quot; <!> quot;回避策<!> quot;には興味がありません。最後に、コンパイラーが魔法のように配列にパッケージ化する文字列の数を渡すか、文字列の配列を直接渡す必要があります。とはいえ、私の解決策は(インターフェイスを変更せずに)次のようになります。
return AppendFolders(new string[] { basefolder, version, callingModule }.Concat(extraFolders).ToArray());
編集:
拡張メソッドを介して演算子を追加することはできませんが、実行できます:
return AppendFolders(new string[] { baseFolder, callingModuleName, version }.Concat(extraFolders));
public static T[] Concat<T>(this T[] a, T[] b) {
return ((IEnumerable<T>)a).Concat(b).ToArray();
}
しかし、ここまで行く場合は、List <!> lt; T <!> gt;を拡張することもできます。これをエレガントに処理するには:
return AppendFolders(new Params<string>() { baseFolder, callingModuleName, version, extraFolders });
class Params<T> : List<T> {
public void Add(IEnumerable<T> collection) {
base.AddRange(collection);
}
public static implicit operator T[](Params<T> a) {
return a.ToArray();
}
}
迅速で汚い解決策は、List <!> lt; string <!> gt;を構築することです。アイテムからそれを渡します(ToArray()で)。
バックスラッシュをテストする必要がないことに注意してください。 Path.Combineは、汚れたものをかなりうまく処理します。
オレゴンゴーストの答えはおそらくあなたが行きたいと思う方法だと思います。詳しく説明するために、彼は次のようなことを提案しています。
public string GetPath(string basefolder, string[] extraFolders)
{
string version = Versioner.GetBuildAndDotNetVersions();
string callingModule = StackCrawler.GetCallingModuleName();
List<string> parameters = new List<string>(extraFolders.Length + 3);
parameters.Add(basefolder);
parameters.Add(version);
parameters.Add(callingModule);
parameters.AddRange(extraFolders);
return AppendFolders(parameters.ToArray());
}
そして、リストを使用する方法についてのレッスンとしてではなく、将来ソリューションを探しにやって来るかもしれない人のためのちょっとした説明として