Различия между тем, как C# и VB обрабатывают названные параметры?

Теперь, когда C# поддерживает названные параметры, я проверял, чтобы видеть, был ли он реализован тем же путем, VB сделал это и нашел, что существуют незначительные различия. Возьмите, например, библиотечную функцию как это:

public static void Foo(string a, string b)
{
    Console.WriteLine(string.Format("a: {0}, b: {1}", a, b));
}

В C#, если Вы называете его как это:

Foo(a: "a", b: "b");

Компилятор производит следующие инструкции IL:

.locals init (
    [0] string CS$0$0000,
    [1] string CS$0$0001)
L_0000: nop 
L_0001: ldstr "a"
L_0006: stloc.0 
L_0007: ldstr "b"
L_000c: stloc.1 
L_000d: ldloc.0 
L_000e: ldloc.1 
L_000f: call void [TestLibrary]TestLibrary.Test::Foo(string, string)
L_0014: nop 
L_0015: ret 

Который переводит в следующий код C#:

string CS$0$0000 = "a";
string CS$0$0001 = "b";
Test.Foo(CS$0$0000, CS$0$0001);

В VB, если Вы называете его как это:

Foo(a:="a", b:="b")

Компилятор производит следующие инструкции IL:

L_0000: nop 
L_0001: ldstr "a"
L_0006: ldstr "b"
L_000b: call void [TestLibrary]TestLibrary.Test::Foo(string, string)
L_0010: nop 
L_0011: nop 
L_0012: ret 

Который переводит в следующий код VB:

Foo("a", "b");

Путем VB делает требуется намного меньше вызовов инструкции, так есть ли какое-либо преимущество для способа, которым C# реализует его? Если Вы не используете именованные параметры, C# производит то же самое как VB.


Править: Теперь, когда мы решили, что дополнительные инструкции уходят в режиме выпуска, есть ли конкретная причина для них присутствовать в режиме отладки? Действия VB, которые то же в обоих режимах и C# не вставляют дополнительные инструкции при вызове метода обычно без именованных параметров (включая то, когда Вы используете дополнительные параметры).

19
задан Greg Shackles 25 February 2010 в 05:33
поделиться

2 ответа

есть ли особая причина для их присутствия в режиме отладки?

Разница между:

  • помещает временное значение в стек , использовать его, отбросить и
  • сохранить временное значение в определенном слоте стека, сделать его копию в стек, использовать, отбросить, но исходная копия временного значения остается в слоте стека

Видимый эффект этого различия заключается в том, что сборщик мусора не может так агрессивно очищать значение. В первом сценарии значение может быть получено сразу после возврата вызова. Во втором сценарии значение собирается только после возврата из текущего метода (или после повторного использования слота).

Уменьшение агрессивности сборщика мусора часто помогает в сценариях отладки.

Подразумевается вопрос:

Почему разница между C # и VB?

Компиляторы C # и VB были написаны разными людьми, которые сделали свой выбор в отношении того, как работают их соответствующие генераторы кода.

ОБНОВЛЕНИЕ: Re: ваш комментарий

В компиляторе C # неоптимизированная генерация IL по существу имеет ту же структуру, что и наше внутреннее представление функции. Когда мы видим именованный аргумент:

M(y : Q(), x : R());

, где метод, скажем,

void M(int x, int y) { }

, мы представляем его внутренне, как если бы вы написали

int ytemp = Q();
int xtemp = R();
M(xtemp, ytemp);

, потому что мы хотим сохранить оценку побочных эффектов Q слева направо. и Р.Это разумное внутреннее представление, и когда мы кодируем его в неоптимизированном режиме, мы просто кодируем код непосредственно из внутреннего представления без каких-либо модификаций.

Когда мы запускаем оптимизатор, мы обнаруживаем всевозможные вещи - например, тот факт, что никто не использует эти невидимые локальные переменные ни для чего. Затем мы можем исключить местных жителей из кодогенератора.

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

Я считаю, что это различие, насколько мне известно, не иллюстрирует важное семантическое различие. Скорее, это показывает, что неоптимизированная сборка просто выплевывает любое высокоуровневое внутреннее представление, которое мы создали, и которое, как мы знаем, имеет желаемую семантику.

13
ответ дан 30 November 2019 в 04:59
поделиться

Компилятор создает следующий код C #:

Нет - компилятор создает IL, который затем переводится в C #. Любое сходство с кодом C # чисто случайно (и не весь сгенерированный IL может быть записан как C #). Наличие всех этих «nop» говорит мне, что вы находитесь в режиме «отладки». Я бы попробовал еще раз в режиме «выпуска» - это может иметь большое значение для этих вещей.

Я запустил его в режиме выпуска, используя:

static void Main()
{
    Foo(a: "a", b: "b");
}

Раздача:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 8
    L_0000: ldstr "a"
    L_0005: ldstr "b"
    L_000a: call void ConsoleApplication1.Program::Foo(string, string)
    L_000f: ret 
}

Так идентично.

5
ответ дан 30 November 2019 в 04:59
поделиться