params 关键字是否支持使用 ValueTuple 作为参数 C# 7.0?

问题描述

我在 StackOverflow 中搜索,没有找到任何文章或与之相关的任何内容。

例如下面的例子描述了数组 ValueTuple

(string CategoryName,params string[] Properties)[]  MyArrayValueTupleParameter  // Compile-Time Syntax error

请注意,前面的示例用作参数。不是变量。

但是只有 string[] 可以在没有参数的情况下工作?我在这里遗漏了什么还是默认不支持?

概览:

这个作品

void ShowAppearanceCategories((string CategoryName,string[] Properties)[] VisibleCategories)
{
    foreach (var Row in PropertyGridControl.Rows)
    {
        var VisibleCategory = VisibleCategories.FirstOrDefault(x => x.CategoryName == Row.Name);
        if (VisibleCategory != default)
        {
            foreach (var ChildRow in Row.ChildRows)
            {
                if (VisibleCategory.Properties.Any(x => ChildRow.Name.Contains(x)))
                {
                    ChildRow.Visible = false;
                }
            }
        }
        else
        {
            Row.Visible = false;
        }
    }
}

这不起作用

void ShowAppearanceCategories((string CategoryName,params string[] Properties)[] VisibleCategories) // Syntax-Error
{
    foreach (var Row in PropertyGridControl.Rows)
    {
        var VisibleCategory = VisibleCategories.FirstOrDefault(x => x.CategoryName == Row.Name);
        if (VisibleCategory != default)
        {
            foreach (var ChildRow in Row.ChildRows)
            {
                if (VisibleCategory.Properties.Any(x => ChildRow.Name.Contains(x)))
                {
                    ChildRow.Visible = false;
                }
            }
        }
        else
        {
            Row.Visible = false;
        }
    }
}

解决方法

在方法签名中,params 关键字必须位于参数列表的开头或前一个参数之后。后面必须跟附加参数的类型。

所以:

ReturnType MethodName(/* arguments */,params Type[] containingArrayName) { /* method body */ }

在您的签名中,您可以看到 params 不在参数声明的开头: void ShowAppearanceCategories((string CategoryName,params string[] Properties)[] VisibleCategories)

这里的额外括号 (string CategoryName,params string[] Properties) 使它更接近元组类型,其中不允许使用 params 关键字导致语法错误。

我不确定您在追求什么,但似乎是这样的:

void ShowAppearanceCategories(params (string CategoryName,string[] Properties)[] VisibleCategories)
,

参数数组是一种非常特殊的语言特性,仅适用于方法参数值元组是一个具有可变长度泛型参数的结构体,并且已经被赋予了用于初始化和使用的特殊语法(其中大部分只是虚张声势)。

var asd = ("asd","asd");

基本上只是语法糖

ValueTuple<string,string> valueTuple = new ValueTuple<string,string>("asd","asd");

命名元组并没有什么特别神奇的地方。

var asd = (bob1 : "asd",bob2 : "asd");
Console.WriteLine(asd.bob1);

基本转换为以下

ValueTuple<string,"asd");
Console.WriteLine(valueTuple.Item1);

所以您本质上是在问,为什么不能在元组初始值设定项语法中使用 params

嗯,正如所讨论的,因为值元组初始值设定项实际上不是一个方法,尽管看起来很像,但您给它的参数不是方法参数。元组语法是它自己非常特殊的语言功能。但是,您确实有选择。

那么让我们看看您要实现的目标。如果您有这样的方法参数

public void Test((string arg1,params string[] args) tuple)

唯一的好处是你可以提供一个逗号分隔的列表。

Test(("bob","args1","args2","args3"));

既然我们做不到,你的选择是

Test(("bob",new []{"args1","args3"}));

或者通过一些愚蠢的操作,您可以在自己的结构上使用显式运算符。

public readonly struct Testing
{
   public Testing(ITuple x)
   {
      CategoryName = (string) x[0];
      Properties = EnumerateTuple<string>(x).ToArray();
   }
   public Testing(string categoryName,string[] properties)
   {
      CategoryName = categoryName;
      Properties = properties;
   }

   private static IEnumerable<T> EnumerateTuple<T>(ITuple x)
   {
      for (var i = 1; i < x.Length; i++)
         yield return (T) x[i];
   }
   public string CategoryName { get; }
   public string[] Properties { get; }
   public static implicit operator Testing((string,string[]) x) => new Testing(x.Item1,x.Item2);
   public static implicit operator Testing(string x) => new Testing(x,Array.Empty<string>());
   public static implicit operator Testing((string,string) x) => new Testing(x);
   public static implicit operator Testing((string,string,string) x) => new Testing(x);
}

这将允许像这样的恶作剧

public static void Test(Testing something)
{
   Console.WriteLine(something.Category);
   Console.WriteLine(string.Join(",",something.Properties);
}

private static void Main(string[] args)
{
   Test("asd");
   Test(("asd"));
   Test(("asd","args1"));
   Test(("asd","args2"));
   Test(("asd","args2"}));
}

注意:这只是为了学术目的,我真的不希望有人想要这样做

,

答案就在你面前......

params 关键字,在这里的其他答案中得到了很好的解释,启用一种方法来接收一组对象(在您的情况下为 string[])。无论您的方法的调用者传递 1 个字符串还是 100 个字符串,您的方法都将获得一个字符串数组。这只是语法糖,让我们的开发者生活更轻松。

但是你的 tuple 已经有一个字符串数组:

(string CategoryName,string[] Properties)

您不需要 params 关键字,因为您已经有了所需的结构:string[]

或者也许这会更好地解释它:这两种方法相同

void DoSomething(string[] Properties) {...}

void DoSomething(params string Properties) {...}

使用这两个方法签名,您将引用 Properties 参数作为 string[]

如果我不清楚,请告诉我。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...