不能使用可变函数作为 Action 的参数 C#

Can't use variadic-function as Action's parameter C#

需要找到一种方法来传递具有 可变数量参数 的委托 Action(请参阅下面的 MyLog)另一种方法(参见 MyLog 下面的 ExtractToDirectory)。

我有一个日志方法:

public static void MyLog(string variable, params object[] args)
{
  textBoxLog.AppendText(string.Format(message, args) + Environment.NewLine);
}

并在同一个 WinForm 中进一步调用 class:

private void buttonInstall_Click(object sender, EventArgs e)
{
  using (Stream zipStream = <Get stream from Resources>)
  using (ZipArchive zip = new ZipArchive(zipStream))
    zip.ExtractToDirectory(@"Z:\", MyLog);
}

静态 class 方法:

public static class ZipFileExtensions
{
  public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, Action<string, params object[]> myLog)
  {
    myLog("Starting {0} extraction", source.Name);
  }
}

问题出在 ExtractToDirectory 的声明上。 params 关键字带有下划线并出现错误:Type expected.

我试着不放参数,但是 VS 需要一个对象数组而不是我需要的可变长度参数。

有线索吗?

删除 'params' 关键字并将其设为 Action<string, object[]>,它可能会编译。 params 只是一个语法糖。函数本身不是 'variadic'。它只需要类型为 object[].

的第二个参数

当然,Action<string, object[]> 在所有情况下都将表现为非 'variadic',它希望您始终提供 new []{..}。 Action/Func 代表不支持 params。不过,您可以创建自己的专门代表:

using System;

public delegate void LogAction(string template, params object[] args);

public static void Log(string a, params object[] args)
{
    System.Console.WriteLine(a,args);
}

public static void Main()
{
    var act = new Action<string,object[]>(Test.Log);
    act("fooo {0} {3}", new object[]{1, 3, 4, 5});

    var myAct = new LogAction(Test.Log);
    myAct("fooo {0} {3}", 1, 3, 4, 5);
}

之后,我得到了这个:


public partial class MainForm : Form
{
  public delegate void LogAction(string message, params object[] args);
  public void Logger(string message, params object[] args)
  {
    if (args != null)
      textBoxLog.AppendText(string.Format(message, args) + Environment.NewLine);
    else
      textBoxLog.AppendText(message + Environment.NewLine);
    Application.DoEvents();
  }

  private void buttonInstall_Click(object sender, EventArgs e)
  {
    Logger("Button clicked");
    using (Stream zipStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(MethodBase.GetCurrentMethod().DeclaringType.Namespace + ".Resources.test.zip"))
    using (ZipArchive zip = new ZipArchive(zipStream))
      zip.ExtractToDirectory(Program.DestinationInstallation, Logger);
}

public static class ZipFileExtensions
{
  public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, MainForm.LogAction myLogger)
  {
    int number = 20180803;
    myLogger("{0} >> {1} (ok)", DateTime.Now, number);
  }
}

非常感谢您的帮助。