2014-09-05 1 views
3

В .NET Framework существует ряд примеров, где существует несколько перегрузок для метода, некоторые из которых используют определенное количество параметров, за которым следует заключительный «catch» all ", где используется ключевое слово params. Типичные примеры этого являются на String классе т.д .:Преимущества использования как определенных аргументов, так и параметров перегрузки метода в C#

Я задавался вопрос, если есть конкретная причина, почему так многие из этих методов перегрузок? Сначала я подумал, что это может быть связано с производительностью; вопрос и ответы на этот вопрос SO - Cost of using params in C# - предложили бы так.

Однако я начал изучать исходный код .NET, используя веб-сайт Reference Source. Я заметил это в String class source code:

String.Concat() действительно запускает другой код в зависимости от того, сколько фиксированных аргументов используется - это, на мой взгляд, определенно будет оптимизацией. String.Format() однако только, кажется, обеспечивает обертки вокруг основного param метода - см ниже для перефразировать кода:

public static String Format(String format, Object arg0) 
{ 
    return Format(format, new Object[] { arg0 }); 
} 

public static String Format(String format, Object arg0, Object arg1) 
{ 
    return Format(format, new Object[] { arg0, arg1 }); 
} 

public static String Format(String format, Object arg0, Object arg1, Object arg2) 
{ 
    return Format(format, new Object[] { arg0, arg1, arg2 }); 
} 

public static String Format(String format, params Object[] args) 
{ 
    // Do work here... 
} 

Так есть преимущества в производительности или это может быть просто вопрос удобства, а может быть, и другое? В конкретном случае выше я не вижу никакой очевидной выгоды, и это, похоже, дублирует работу.

+0

Сохраняет несколько байтов IL в каждом вызывающем абоненте: нет необходимости выделять и инициализировать массив. –

+0

@MichaelLiu Но это * * выделяет и инициализирует массив здесь, он просто делает это внутри нового метода, а не снаружи. – Servy

+0

@Servy: он сохраняет несколько байтов IL в каждом * вызывающем *. То есть, на каждом сайте вызова компилятор должен только генерировать инструкции для ввода аргументов. Если не было выделенных перегрузок, компилятор также должен был бы генерировать инструкции для выделения и инициализации массива. –

ответ

1

Обновление: его не String.Concat, но String.Format.

Я думаю, причина в том, что все вызовы заканчиваются в StringBuilder.AppendFormat, который является довольно сложным и будет основным источником дублирования кода, если вы будете обрабатывать каждое количество входных аргументов по-другому.

Все по-другому, если у вас есть сверхмощный API (например, трассировка), где накладные расходы на вызов метода с помощью перегрузки параметров очень значительны. Это может быть до 5 раз. То же самое касается неявных распределений делегатов, что является общим с LINQ. Эти временные экземпляры делегатов не являются дешевыми в оптимизированном коде. Например, Roslyn запретил использование LINQ из-за высоких неявных затрат на размещение делегатов.

+0

Если бы было сочтено слишком много работы, чтобы реально реализовать каждую разную перегрузку, то почему бы просто не начать перегрузку? – Servy

+0

Если вы предоставили уже все перегрузки, вы можете изменить реализацию позже, если кто-то придумает отличную идею. Если позже вы предоставите эти перегрузки, вам нужно будет перекомпилировать каждое приложение, чтобы использовать улучшенные перегрузки. –

+0

Спасибо @AloisKraus, это, кажется, самое близкое, что я ожидал ответа. Не могли бы вы объяснить, почему «params» хуже? например если бы у меня были оба 'String.Format (" {0}, {1} ", 1, 2)' и 'String.Format (" {0}, {1} ", новый объект [] {1, 2}) 'они точно такие же или есть разница в этих вызовах тоже? –

2

Это позволяет создавать делегат каждый из этих подписей, которые вызывают этот метод:

Func<string, object, object> foo = string.Format; 

Это не будет работать с методом params; вы можете назначить эту перегрузку только Func<string, object[]> или делегату, который специально предоставил params в своей подписи. Вам нужно будет создать новый метод, который просто вызвал перегрузку params, чтобы создать делегат подписи, используемой в его примере (возможно, с помощью лямбда).

+0

Хотя выделенные перегрузки делают это возможным, я сомневаюсь, что это настоящая причина, по которой команда .NET создала выделенные перегрузки в этом конкретном случае. –

+0

@MichaelLiu Согласен. – Servy

+0

Действительно ли ключевое слово 'params' останавливает создание делегата? Я бы предположил, что это будет просто «Func '? – DavidG

 Смежные вопросы

  • Нет связанных вопросов^_^