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

dev*_*ton 3 .net c# tuples c#-7.0 valuetuple

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

例如,下面的示例描述了ValueTuple数组

(string CategoryName, params string[] Properties)[]  MyArrayValueTupleParameter  // Compile-Time Syntax error
Run Code Online (Sandbox Code Playgroud)

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

但只有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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AAA*_*ddd 5

参数数组是一种非常具体的语言功能,仅适用于方法参数。值元是一个具有可变长度泛型参数的结构,并且已被赋予特殊的初始化和使用语法(其中大多数只是冒牌货)。

var asd = ("asd","asd");
Run Code Online (Sandbox Code Playgroud)

基本上只是语法糖

ValueTuple<string, string> valueTuple = new ValueTuple<string, string>("asd", "asd");
Run Code Online (Sandbox Code Playgroud)

命名元组甚至没有什么过于神奇的地方。

var asd = (bob1 : "asd", bob2 : "asd");
Console.WriteLine(asd.bob1);
Run Code Online (Sandbox Code Playgroud)

基本上转化为以下

ValueTuple<string, string> valueTuple = new ValueTuple<string, string>("asd", "asd");
Console.WriteLine(valueTuple.Item1);
Run Code Online (Sandbox Code Playgroud)

所以你本质上是在问,为什么不能params在元组初始化语法中使用。

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

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

public void Test((string arg1, params string[] args) tuple)
Run Code Online (Sandbox Code Playgroud)

唯一的优点是您可以提供逗号分隔的列表。

Test(("bob","args1","args2","args3"));
Run Code Online (Sandbox Code Playgroud)

既然我们不能,你的选择是

Test(("bob",new []{"args1","args2","args3"}));
Run Code Online (Sandbox Code Playgroud)

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

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 implicit operator Testing((string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string, string, string, string, string, string) x) => new Testing(x);
   public static implicit operator Testing((string, string, string, string, string, string, string, string, string, string, string, string) x) => new Testing(x);
}
Run Code Online (Sandbox Code Playgroud)

这会允许这样的恶作剧

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", "args1", "args2"));
   Test(("asd", new []{"args1", "args2"}));
}
Run Code Online (Sandbox Code Playgroud)

注意:这仅用于学术目的,我真的不希望有人愿意这样做