May 29, 2007

C# в стиле JavaScript

Пару дней назад я писал о том, как можно нетрадиционно использовать возможности анонимных делегатов в C# 2.0. То есть не то, чтобы нетрадиционно, но в стиле JavaScript.

Настало время посмотреть как подобное извращение влияет на скомпилированный код. Для этого напишем небольшой примерчик.

using System;

public class App{

private static Action<string> _actionAsDelegate = delegate(string text){
return;
};

private static void _actionAsStaticMethod(string text){
return;
}

private void _actionAsMethod(string text){
return;
}

public static void Main(string[] args){
_actionAsDelegate(string.Empty);
_actionAsStaticMethod(string.Empty);
(new App())._actionAsMethod(string.Empty);
}

}

На всякий случай объясню немножко, чего я пытаюсь сказать. Итак: надо выполнить какое-то действие над строкой. Первый вариант - это простой метод _actionAsMethod, а второй - _actionAsDelegate, который на самом деле всего лишь переменная, которой присвоен анонимный делегат. В JavaScript такое объявление вполне нормально и иногда даже более правильно, чем объявление функции стандартным путём. На всякий случай, я написал ещё _actionAsStaticMethod, просто для того, чтобы сравнить результаты.


Компилируем и смотрим, что скажет по этому поводу ILDASM.


.method public hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size 45 (0x2d)
.maxstack 8
IL_0000: nop
IL_0001: ldsfld class [mscorlib]System.Action`1<string> App::_actionAsDelegate
IL_0006: ldsfld string [mscorlib]System.String::Empty
IL_000b: callvirt instance void class [mscorlib]System.Action`1<string>::Invoke(!0)
IL_0010: nop
IL_0011: ldsfld string [mscorlib]System.String::Empty
IL_0016: call void App::_actionAsStaticMethod(string)
IL_001b: nop
IL_001c: newobj instance void App::.ctor()
IL_0021: ldsfld string [mscorlib]System.String::Empty
IL_0026: call instance void App::_actionAsMethod(string)
IL_002b: nop
IL_002c: ret
} // end of method App::Main

Сейчас сразу не вспомню где конкретно, но я где-то определённо читал, что анонимные делегаты превращаются компилятором в методы. А тут что-то совсем сложное. Одно ясно однозначно: вызов _actionAsDelegate дороже вызова _actionAsMethod, хотя бы потому, что он виртуальный. Для полной достоверности, надо бы, наверное, провести замеры времени при 1_000_000 итераций, но я этим заниматься не стану. Для меня главное - уяснить, что JavaScript'овые штучки в C# "не пройдут", что в общем-то, и правильно. Каждому - своё.


This page is powered by Blogger. Isn't yours?