C# 可变长度 args,哪个更好,为什么:__arglist、params 数组或 Dictionary<T,K>?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/910585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# variable length args, which is better and why: __arglist, params array or Dictionary<T,K>?
提问by mkelley33
I recently read the following overflow post: Hidden Features of C#
我最近阅读了以下溢出帖子: C# 的隐藏功能
One of the features pointed out was the arglist. Why would one choose this or the alternatives as a means of using a variable length argument list to a method? Also, note that I would probably not use this kind of construct in my code unless a corner case warranted doing so. This is more of a question of semantics than whether it is even practical or prudent to even use variable length arguments. So does anyone know which is better and why?
指出的功能之一是 arglist。为什么要选择这个或替代方案作为将可变长度参数列表用于方法的一种方式?另外,请注意,除非特殊情况需要这样做,否则我可能不会在我的代码中使用这种构造。这更多是一个语义问题,而不是使用可变长度参数是否实用或谨慎。那么有谁知道哪个更好,为什么?
[Test]
public void CanHandleVariableLengthArgs()
{
TakeVariableLengthArgs(__arglist(new StringBuilder(), 12));
object[] arr = { new StringBuilder() };
TakeVariableLengthArgs2(arr);
TakeVariableLengthArgs3(
new Dictionary<string, object>
{ { "key", new StringBuilder() } });
}
public void TakeVariableLengthArgs(__arglist)
{
var args = new ArgIterator(__arglist);
var a = (StringBuilder)TypedReference.ToObject(args.GetNextArg());
a.Append(1);
}
public void TakeVariableLengthArgs2(params object[] args)
{
var a = (StringBuilder)args[0];
a.Append(1);
}
public void TakeVariableLengthArgs3(Dictionary<string, object> args)
{
var a = (StringBuilder)args["StringBuilder"];
a.Append(1);
}
采纳答案by John Saunders
I would certainly never use __arglist, since it's undocumented and nobody knows what it means in any case.
我当然永远不会使用 __arglist,因为它没有记录,而且在任何情况下都没有人知道它的含义。
I'd also avoid variable-length argument lists for as long as possible, and instead rework my design to understand what is truly variable, and to model that variability in a less platform-dependant manner.
我还尽可能避免使用可变长度的参数列表,而是重新设计我的设计以了解什么是真正可变的,并以不太依赖平台的方式对可变性进行建模。
回答by krosenvold
I would prefer to not use anyof the three techniques described here. I would instead design a value object that has strong types wherever possible, and possibly even nullable types. If push comes to shove you can create a generics-typed value object too.
我宁愿不使用这里描述的三种技术中的任何一种。相反,我会设计一个尽可能具有强类型的值对象,甚至可能是可为空类型。如果迫不得已,您也可以创建一个泛型类型的值对象。
There's just all so much code smell in this way of coding for me. A variable lengthcollection of object? Wouldn't pass unnoticed in mycode review.
对我来说,这种编码方式有太多的代码味道。甲可变长度的收集对象?在我的代码中不会被忽视。
Edit: And if it DID pass my code review the parameter would in all likelyhood be an IEnumerable instance and none of the three suggestions items. IEnumerable is the leanest thing that could encapsulate my needs.
编辑:如果它确实通过了我的代码,则参数很可能是一个 IEnumerable 实例,并且三个建议项都没有。IEnumerable 是可以封装我的需求的最精简的东西。
回答by plinth
It depends on the case. I've used params in cases where I have a variable number of arguments and it significantly adds to the readability of the calling code.
视情况而定。我在参数数量可变的情况下使用了 params,它显着增加了调用代码的可读性。
For example, I have a class that represents a TIFF document and allows access to a collection of pages which can be reordered and interspersed with other TIFF documents. Since one of the most common tasks our customers want is the ability to easily combine multiple TIFF documents into a single, we also provide the following two utility methods:
例如,我有一个表示 TIFF 文档的类,它允许访问一组页面,这些页面可以重新排序并与其他 TIFF 文档穿插。由于我们客户最常见的任务之一是能够轻松地将多个 TIFF 文档合并为一个,因此我们还提供了以下两种实用方法:
public static void Combine(Stream output, params Stream[] sources) { /* ... */ }
public static void Combine(Stream output, params string[] sourceFiles) { /* ... */ }
which in usage make the client code feel really nice:
在使用中使客户端代码感觉非常好:
using (FileStream output = new FileStream(outputPath, FileMode.Create)) {
TiffDocument.Combine(output, tpsCoverSheetPath, mainDocumentPath, tpsTrailerPath);
}
回答by LBushkin
In general, you are probably better off avoiding undocumented features of the language - for several reasons.
通常,出于多种原因,您最好避免使用该语言的未记录功能。
- They are more likely to change then the established, documented features
- They may have side-effects and implications that are not obvious in their usage
- Other developers will not be familiar with them and will have a harder time maintaining your code
- Refactoring tools (like VS itself or Resharper) are unlikely to be able to recognize them
- They take away clarity from the intent of your code
- There are language-supported alternatives to most of them
- 与已建立的、记录在案的功能相比,它们更有可能改变
- 它们可能具有在使用中不明显的副作用和影响
- 其他开发人员不会熟悉它们,并且会更难维护您的代码
- 重构工具(如 VS 本身或Resharper)不太可能识别它们
- 它们使您的代码意图变得清晰
- 大多数都有语言支持的替代品
In the specific case of the __arglist, you can achieve the same capabilities with the language supported paramskeyword, which allows you to create type-safe variable argument lists for methods in C#. As a practice, though, I would be careful using it as it can obfuscate your code if used inpropertly - good use cases (like those in string.Format() which accepts variable arguments) - are less frequent than you would think.
在 __arglist 的特定情况下,您可以使用语言支持的params关键字实现相同的功能,这允许您为 C# 中的方法创建类型安全的变量参数列表。但是,作为一种实践,我会小心使用它,因为如果使用不当,它可能会混淆您的代码 - 好的用例(例如 string.Format() 中接受可变参数的用例) - 比您想象的要少。
回答by bzlm
C# 4 will have a better mechanism for this; named and optional arguments:
C# 4 将有一个更好的机制;命名和可选参数:
static void Main(string[] args)
{
// The method can be called in the normal way, by using positional arguments.
Console.WriteLine(CalculateBMI(123, 64));
// Named arguments can be supplied for the parameters in either order.
Console.WriteLine(CalculateBMI(weight: 123, height: 64));
Console.WriteLine(CalculateBMI(height: 64, weight: 123));
// Positional arguments cannot follow named arguments.
// The following statement causes a compiler error.
//Console.WriteLine(CalculateBMI(weight: 123, 64));
// Named arguments can follow positional arguments.
Console.WriteLine(CalculateBMI(123, height: 64));
}
static int CalculateBMI(int weight, int height)
{
return (weight * 703) / (height * height);
}