params 关键字是否支持将 ValueTuple 作为参数 C# 7.0?
Is params Keyword supports with ValueTuple as a parameter C# 7.0?
我在 Whosebug 中搜索,没有找到任何文章或与此相关的任何内容。
例如下面的例子描述了array of 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)
参数数组是一种非常特殊的语言特性,仅适用于方法参数。 value tuple 是一个具有可变长度通用参数的结构,并被赋予了用于初始化和使用的特殊语法(其中大部分只是冒烟的镜子)。
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, string> valueTuple = new ValueTuple<string, string>("asd", "asd");
Console.WriteLine(valueTuple.Item1);
所以你本质上是在问,为什么你不能在元组初始化语法中使用 params
。
好吧,正如所讨论的,因为值元组初始化程序实际上不是方法,而且尽管看起来很像,但您给它的参数不是方法参数。元组语法是它自己非常特殊的语言特性。但是,您确实有选择。
那么让我们看看您要实现的目标。如果你有这样的方法参数
public void Test((string arg1, params string[] args) tuple)
唯一的好处是您可以提供逗号分隔的列表。
Test(("bob","args1","args2","args3"));
既然我们不能,你的选择是
Test(("bob",new []{"args1","args2","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 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);
}
这会允许这样的恶作剧
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"}));
}
注意 : 这只是为了学术目的,我真的不希望有人想这样做
答案就在你面前...
params
关键字,这里的其他答案很好地解释了,启用一种方法来接收对象数组(在你的情况下string[]
).无论您的方法的调用者传递 1 个字符串还是 100 个字符串,您的方法都将获得一个字符串数组。这只是 语法糖 让我们作为开发人员的生活更轻松。
但是你的tuple
已经一个字符串数组:
(string CategoryName, string[] Properties)
您不需要 params
关键字,因为您已经拥有所需的结构:string[]
.
或者这可能会更好地解释:这两种方法 相同:
void DoSomething(string[] Properties) {...}
void DoSomething(params string Properties) {...}
使用这两个方法签名,您将引用 Properties
参数作为 string[]
。
如果我不清楚,请告诉我。
我在 Whosebug 中搜索,没有找到任何文章或与此相关的任何内容。
例如下面的例子描述了array of 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)
参数数组是一种非常特殊的语言特性,仅适用于方法参数。 value tuple 是一个具有可变长度通用参数的结构,并被赋予了用于初始化和使用的特殊语法(其中大部分只是冒烟的镜子)。
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, string> valueTuple = new ValueTuple<string, string>("asd", "asd");
Console.WriteLine(valueTuple.Item1);
所以你本质上是在问,为什么你不能在元组初始化语法中使用 params
。
好吧,正如所讨论的,因为值元组初始化程序实际上不是方法,而且尽管看起来很像,但您给它的参数不是方法参数。元组语法是它自己非常特殊的语言特性。但是,您确实有选择。
那么让我们看看您要实现的目标。如果你有这样的方法参数
public void Test((string arg1, params string[] args) tuple)
唯一的好处是您可以提供逗号分隔的列表。
Test(("bob","args1","args2","args3"));
既然我们不能,你的选择是
Test(("bob",new []{"args1","args2","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 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);
}
这会允许这样的恶作剧
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"}));
}
注意 : 这只是为了学术目的,我真的不希望有人想这样做
答案就在你面前...
params
关键字,这里的其他答案很好地解释了,启用一种方法来接收对象数组(在你的情况下string[]
).无论您的方法的调用者传递 1 个字符串还是 100 个字符串,您的方法都将获得一个字符串数组。这只是 语法糖 让我们作为开发人员的生活更轻松。
但是你的tuple
已经一个字符串数组:
(string CategoryName, string[] Properties)
您不需要 params
关键字,因为您已经拥有所需的结构:string[]
.
或者这可能会更好地解释:这两种方法 相同:
void DoSomething(string[] Properties) {...}
void DoSomething(params string Properties) {...}
使用这两个方法签名,您将引用 Properties
参数作为 string[]
。
如果我不清楚,请告诉我。