¿Es posible explotar una matriz para que sus elementos puedan pasarse a un método con la palabra clave params?

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

Pregunta

Tome este código que no compila, por ejemplo:

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 ejemplo es una versión algo simplificada del código de prueba que estoy usando. Por favor, solo estoy interesado en soluciones que tengan que ver directamente con la palabra clave param. Sé cómo funcionan las listas y otras cosas similares.

¿Hay alguna forma de " explotar " la matriz extraFolders para que su contenido se pueda pasar a AppendFolders junto con otros parámetros?

¿Fue útil?

Solución

Una opción es hacer que el parámetro params sea 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('\\')));
 }

Si desea algo más fuertemente tipado, otra opción es crear un tipo de unión personalizada con operadores de conversión 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};}
     }

En cualquier caso, este compilará :

appendFolders("base", "v1", "module", new[]{"debug","bin"});

Otros consejos

Solo pásalo. El parámetro de carpetas es una matriz primero. " params " la funcionalidad es un poco de magia de compilación, pero no es necesaria.

AppendFolders(extraFolders);

Ahora, en esta instancia particular, primero tendrá que agregar algunas cosas a esa matriz.

List<string> lstFolders = new List<string>(extraFolders);
lstFolder.Insert(0, callingModule);
lstFolder.Insert(0, version);
lstFolder.Insert(0, basefolder);
return AppendFolders(lstFolders.ToArray());

Discutiré con el término " collapse " ;, ya que parece que realmente quieres " expandir " ;. Y no estoy seguro de lo que quiere decir con soluciones & Quot; que tienen que ver directamente con la palabra clave params & Quot; y que " no le interesan las soluciones " ;. Al final, tienes que pasar una serie de cadenas, que el compilador empacará mágicamente en una matriz, o una matriz de cadenas directamente. Dicho esto, mi solución (sin cambiar la interfaz) sería algo así como:

return AppendFolders(new string[] { basefolder, version, callingModule }.Concat(extraFolders).ToArray());

Editar:

Si bien no puede agregar un operador a través de métodos de extensión, puede hacer lo siguiente:

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();
}

Pero, si vamos a llegar tan lejos, también podríamos extender List < T > para manejar esto con elegancia:

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();
    }
}

Una solución rápida y sucia sería construir una Lista < string > de los elementos y luego pasar eso (con ToArray ()).

Tenga en cuenta que no necesita probar la barra invertida. Path.Combine maneja las cosas sucias bastante bien .

Creo que la respuesta de OregonGhost es probablemente la forma en que quieres ir. Solo para explicarlo, sugiere hacer algo como esto:

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());
}

Y no me refiero a eso como una lección sobre cómo usar las Listas, solo como una pequeña aclaración para cualquiera que pueda venir a buscar la solución en el futuro.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top