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-это самая худшая вещь, которая может инкапсулировать мои потребности.