É possível explodir uma matriz para que seus elementos podem ser passados ??para um método com o params palavra-chave?
-
08-07-2019 - |
Pergunta
Tome este código não compilar, por exemplo:
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;
}
Este exemplo é uma versão um pouco simplificada de testar código que estou usando. Por favor, eu só estou interessado em soluções tendo directamente a ver com a palavra-chave param. Eu sei como listas e outras coisas semelhantes de trabalho.
Existe uma maneira de "explodir" a matriz extraFolders para que o seu conteúdo pode ser passado para AppendFolders juntamente com outros parâmetros?
Solução
Uma opção é fazer o params
parâmetro um 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('\\')));
}
Se você quiser algo mais fortemente tipado, outra opção é criar um tipo de união aduaneira com os operadores de conversão implícitos:
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};}
}
Em ambos os casos, este compilação:
appendFolders("base", "v1", "module", new[]{"debug","bin"});
Outras dicas
Apenas passá-lo. O parâmetro pastas é uma matriz em primeiro lugar. o "params" funcionalidade é um pouco de magia do compilador, mas isso não é obrigatório.
AppendFolders(extraFolders);
Agora, neste caso particulat, você terá que adicionar algumas coisas a essa matriz, em primeiro lugar.
List<string> lstFolders = new List<string>(extraFolders);
lstFolder.Insert(0, callingModule);
lstFolder.Insert(0, version);
lstFolder.Insert(0, basefolder);
return AppendFolders(lstFolders.ToArray());
Eu vou tergiversar com o termo "colapso", uma vez que parece que você realmente quer "expandir". E eu não tenho certeza do que você quer dizer com soluções "tendo directamente a ver com params palavra-chave" e que "você não está interessado em soluções alternativas". No final, você tem que passar uma série de cordas - que o compilador irá magicamente pacote em uma matriz - ou um conjunto de cordas diretamente. Dito isto, a minha solução (sem alterar a interface) seria algo como:
return AppendFolders(new string[] { basefolder, version, callingModule }.Concat(extraFolders).ToArray());
Editar:
Enquanto você não pode adicionar um operador através de métodos de extensão, você poderia fazer:
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();
}
Mas, se nós estamos indo para ir tão longe - pode muito bem estender 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();
}
}
Uma solução rápida e suja seria a construção de um List
Note que você não precisa de teste para a barra invertida. alças Path.Combine as coisas sujas bastante fino .
Eu acho que a resposta de OregonGhost é provavelmente a maneira que você quer ir. Só para elaborar sobre isso, ele está sugerindo fazer algo como isto:
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());
}
E eu não quero dizer que como uma lição sobre como usar listas, assim como um pouco de esclarecimento para quem pode vir procurando a solução no futuro.