【问题标题】:Is it possible to explode an array so that its elements can be passed to a method with the params keyword?是否可以分解数组,以便可以将其元素传递给带有 params 关键字的方法?
【发布时间】:2008-10-10 19:19:50
【问题描述】:

以这段非编译代码为例:

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 中?

【问题讨论】:

  • 只是为了确保我理解,您希望将 extraFolders 数组作为 AppendFolders(extraFolders[0], extraFolders[1], ...etc etc) 发送到 AppendFolders 方法?有趣的问题,我很好奇这是否可能,虽然我不知道如何......
  • 您的澄清只会增加更多的困惑。传递的额外项目是否是其中的重要部分?如果没有,我的答案的前半部分就是你想要的。如果是,这是一个非常特殊的情况,由我回答的后半部分处理。
  • 两者都很重要,但它们使用的上下文并不重要。我想说的是我不在乎它们是路径还是我正在使用 Path.Combine,我只想要一个简单的单线器将两组参数组合在一起,以便可以将它们传递给 params 方法。

标签: c# parameters keyword variadic-functions params-keyword


【解决方案1】:

只是通过它。文件夹参数首先是一个数组。 “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());

【讨论】:

  • 我猜关键是你不能只向数组中添加东西:)
【解决方案2】:

我会对“崩溃”这个词提出质疑,因为您似乎真的想要“扩展”。而且我不确定您所说的解决方案“与 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();
    }
}

【讨论】:

  • 这真的很接近我想要的。优雅且类似于编译器可能会做的事情。
  • 同样酷的是:new string[] { baseFolder, callingModuleName, version } + extraFolders
【解决方案3】:

一种选择是将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"});

【讨论】:

    【解决方案4】:

    一个快速而肮脏的解决方案是从项目构建一个 List 然后传递它(使用 ToArray())。

    请注意,您不需要测试反斜杠。 Path.Combine 处理the dirty things rather fine

    【讨论】:

    • 在某些情况下它不能正确处理反斜杠。过去,我以双反斜杠告终。前任。废话\\废话
    • 那么它可能是一个错误,您可以在connect.microsoft.com 上提交 - 如果您想继续使用反斜杠,至少使用 Path.DirectorySeparatorChar 而不是硬编码的反斜杠。
    • 如果第二个路径以反斜杠开头,Path.Combine 会出现问题。
    【解决方案5】:

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

    我并不是说这是关于如何使用列表的一课,只是为将来可能前来寻找解决方案的任何人提供一点说明。

    【讨论】:

      猜你喜欢
      • 2012-06-03
      • 2011-01-22
      • 2017-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-26
      • 2011-04-22
      相关资源
      最近更新 更多