Можно ли взорвать массив, чтобы его элементы могли быть переданы методу с ключевым словом params?
Возьмите этот некомпилируемый код, например:
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. Я знаю, как работают списки и другие подобные вещи.
Есть ли способ "взорвать" массив extraFolders, чтобы его содержимое могло быть передано в AppendFolders вместе с другими параметрами?
5 ответов
Одним из вариантов является сделать 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 сначала является массивом. функциональность "params" - это немного волшебства компилятора, но это не обязательно.
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());
Я буду спорить с термином "коллапс", так как кажется, что вы действительно хотите "расширить". И я не уверен, что вы подразумеваете под решениями, "имеющими непосредственное отношение к ключевому слову params" и тем, что "вы не заинтересованы в обходных решениях". В конце вы должны либо передать несколько строк, которые компилятор волшебным образом упакует в массив, либо непосредственно в массив строк. При этом мое решение (без изменения интерфейса) будет выглядеть примерно так:
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
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();
}
}
Я думаю, что OregonGhost ответ, вероятно, так, как вы хотите пойти. Просто чтобы уточнить это, он предлагает сделать что-то вроде этого:
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());
}
И я не имею в виду это как урок о том, как использовать списки, просто как небольшое разъяснение для тех, кто может прийти к поиску решения в будущем.
Быстрое и грязное решение состоит в том, чтобы создать List
Обратите внимание, что вам не нужно проверять обратную косую черту. Path.Combine справляется с грязными вещами довольно хорошо.