Args переменной длины C#, что лучше и почему: arglist, массив params или словарь?
недавно я прочитал следующее сообщение переполнения: скрытые возможности C#
одной из указанных функций был arglist. Почему бы выбрать это или альтернативы в качестве средства использования списка аргументов переменной длины для метода? Также обратите внимание, что я, вероятно, не использовать этот вид конструкции в своем коде, если случай заслуживает этого. Это скорее вопрос семантики, чем того, практично или разумно даже использовать переменную аргумент length. Кто-нибудь знает, что лучше и почему?
[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);
}
5 ответов
Я бы, конечно, никогда не использовал __arglist, так как он недокументирован, и никто не знает, что это значит в любом случае.
Я бы также избегал списков аргументов переменной длины как можно дольше и вместо этого переработал свой дизайн, чтобы понять, что действительно является переменным, и моделировать эту изменчивость менее зависимым от платформы способом.
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);
}
Это зависит от случая. Я использовал params в случаях, когда у меня есть переменное число аргументов и это значительно увеличивает читабельность кода вызова.
например, у меня есть класс, который представляет документ TIFF и позволяет получить доступ к коллекции страниц, которые могут быть переупорядочены и перемежаются с другими документами TIFF. Поскольку одной из наиболее распространенных задач наших клиентов является возможность легко объединить несколько документов TIFF в один, мы также предоставьте следующие два метода утилиты:
public static void Combine(Stream output, params Stream[] sources) { /* ... */ }
public static void Combine(Stream output, params string[] sourceFiles) { /* ... */ }
которые в использовании делают клиентский код очень приятным:
using (FileStream output = new FileStream(outputPath, FileMode.Create)) {
TiffDocument.Combine(output, tpsCoverSheetPath, mainDocumentPath, tpsTrailerPath);
}
В общем, вам, вероятно, лучше избегать недокументированных особенностей языка - по нескольким причинам.
- они с большей вероятностью изменятся, чем установленные, документированные функции
- Они могут иметь побочные эффекты и последствия, которые не очевидны в их использовании
- другие разработчики не будут знакомы с ними и им будет сложнее поддерживать ваш код
- инструменты рефакторинга (например, VS или Resharper) вряд ли смогут их распознать
- Они отнимают ясность от намерения вашего кода
- существуют языковые альтернативы большинству из них
в конкретном случае _ _ arglist, вы можете достичь тех же возможностей с поддерживаемым языком params ключевое слово, которое позволяет создавать типобезопасные списки аргументов переменных для методов в C#. Хотя, как практика, я бы осторожно используйте его, поскольку он может запутать ваш код, если используется inpropertly-хорошие случаи использования (например, в string.Format (), который принимает переменные аргументы) - реже, чем вы думаете.
Я бы предпочел не использовать любой из трех методов, описанных здесь. Вместо этого я бы разработал объект value, который имеет сильные типы, где это возможно, и, возможно, даже типы nullable. Если дойдет до толчка, вы также можете создать объект значения, типизированный generics.
в этом способе кодирования для меня так много запаха кода. А переменной длины коллекция объект ? Не пройдет незамеченным в мой код обзор.
редактировать: И если бы он прошел мой обзор кода, параметр, скорее всего, был бы экземпляром IEnumerable и ни один из трех элементов предложений. IEnumerable-это самая худшая вещь, которая может инкапсулировать мои потребности.