确保可变参数方法至少需要一个参数的最简洁方法是什么?
What's the cleanest way to ensure a varargs method requires at least one parameter?
给定以下扩展方法:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
return second.Concat(first);
}
我会写:
var foo = new[] { "cd", "ef", }.Prepend("ab");
产生所需的:
{ "ab", "cd", "ef", }
很好,但我也可以写:
var bar = new[] { "cd", "ef", }.Prepend();
这是完全荒谬但仍然有效的代码。我想防止这样滥用我的方法。
我可以将方法重写为以下内容:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, T second, params T[] third)
{
return new[] { second, }.Concat(third).Concat(first);
}
但是我必须在正文中决定我是否要组合 second
和 third
然后 .Concat
它们,或者我是否想做多个 .Concat
电话。无论哪种方式,都涉及数组创建和额外的方法调用,这不是最优的。
This answer 提出了一种简单而新颖的方法来解决这个问题 - 声明一个无参数方法重载并将其标记为 Obsolete
以便它生成编译错误:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
return second.Concat(first);
}
[Obsolete("Don't use this method, it always throws.", true)]
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first)
{
throw new InvalidOperationException();
}
现在使用不带参数的方法会选择具体的重载并在我尝试编译时失败 - VS2015 甚至给我 IntelliSense 告诉我我做错了™:
// compiler says yes
var foo = new[] { "cd", "ef", }.Prepend("ab");
// compiler says NO
var bar = new[] { "cd", "ef", }.Prepend();
问题是,这感觉像是一个 hack。我更希望能够写出如下内容:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, [MinLength(1)] params T[] second)
{
return second.Concat(first);
}
这更直观。不幸的是,C# 中开箱即用的属性不提供编译时验证,我不想为这样一个简单的用例引入 PostSharp 或 LinFu 之类的东西。
所以我的问题是:在默认情况下,沼泽标准,C# 6 是否有任何方法可以实现这一点?
一个选项是添加 Roslyn 分析器 - 这允许您生成任意编译器错误。
另一种选择是手动添加第一个参数:
public static IEnumerable<T> Prepend<T>
(this IEnumerable<T> @this, T first, params T[] rest)
但这很好地说明了为什么这是一个糟糕的想法的原因 - 这意味着当您使用动态参数调用方法时,您必须手动将数组拆分为第一个参数和其余参数。您真的要强制您的方法的所有用户检查他们传递的数组是否不为空吗?为什么?您的方法可以轻松处理这两种情况。你真的认为任意限制值得吗?没有其他 LINQ 风格的方法是这样工作的——你可能会造成比你正在解决的更多的麻烦(在我看来,你没有解决 any 问题)。
目前没有比支持 AOP(面向方面编程)的工具(如 PostSharp)更好的解决方案了。我会选择那个选项。
另一种选择可能是将其从代码库中提取出来并创建一个 Roslyn code analyzer 来为您执行 'quality' 检查。在我看来这不是理想的选择,但如果您不想使用 PostSharp,这可能是一个选择。
给定以下扩展方法:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
return second.Concat(first);
}
我会写:
var foo = new[] { "cd", "ef", }.Prepend("ab");
产生所需的:
{ "ab", "cd", "ef", }
很好,但我也可以写:
var bar = new[] { "cd", "ef", }.Prepend();
这是完全荒谬但仍然有效的代码。我想防止这样滥用我的方法。
我可以将方法重写为以下内容:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, T second, params T[] third)
{
return new[] { second, }.Concat(third).Concat(first);
}
但是我必须在正文中决定我是否要组合 second
和 third
然后 .Concat
它们,或者我是否想做多个 .Concat
电话。无论哪种方式,都涉及数组创建和额外的方法调用,这不是最优的。
This answer 提出了一种简单而新颖的方法来解决这个问题 - 声明一个无参数方法重载并将其标记为 Obsolete
以便它生成编译错误:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
return second.Concat(first);
}
[Obsolete("Don't use this method, it always throws.", true)]
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first)
{
throw new InvalidOperationException();
}
现在使用不带参数的方法会选择具体的重载并在我尝试编译时失败 - VS2015 甚至给我 IntelliSense 告诉我我做错了™:
// compiler says yes
var foo = new[] { "cd", "ef", }.Prepend("ab");
// compiler says NO
var bar = new[] { "cd", "ef", }.Prepend();
问题是,这感觉像是一个 hack。我更希望能够写出如下内容:
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, [MinLength(1)] params T[] second)
{
return second.Concat(first);
}
这更直观。不幸的是,C# 中开箱即用的属性不提供编译时验证,我不想为这样一个简单的用例引入 PostSharp 或 LinFu 之类的东西。
所以我的问题是:在默认情况下,沼泽标准,C# 6 是否有任何方法可以实现这一点?
一个选项是添加 Roslyn 分析器 - 这允许您生成任意编译器错误。
另一种选择是手动添加第一个参数:
public static IEnumerable<T> Prepend<T>
(this IEnumerable<T> @this, T first, params T[] rest)
但这很好地说明了为什么这是一个糟糕的想法的原因 - 这意味着当您使用动态参数调用方法时,您必须手动将数组拆分为第一个参数和其余参数。您真的要强制您的方法的所有用户检查他们传递的数组是否不为空吗?为什么?您的方法可以轻松处理这两种情况。你真的认为任意限制值得吗?没有其他 LINQ 风格的方法是这样工作的——你可能会造成比你正在解决的更多的麻烦(在我看来,你没有解决 any 问题)。
目前没有比支持 AOP(面向方面编程)的工具(如 PostSharp)更好的解决方案了。我会选择那个选项。
另一种选择可能是将其从代码库中提取出来并创建一个 Roslyn code analyzer 来为您执行 'quality' 检查。在我看来这不是理想的选择,但如果您不想使用 PostSharp,这可能是一个选择。