É possível explodir uma matriz para que seus elementos podem ser passados ??para um método com o params palavra-chave?

StackOverflow https://stackoverflow.com/questions/192715

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?

Foi útil?

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 para lidar com este elegantemente:

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 a partir dos itens e, em seguida, passar essa (com ToArray ()).

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top