Я проверял некоторые из кода, которые составляют расширения LINQ в Reflector, и это тот код, с которым я сталкиваюсь:
private bool MoveNext()
{
bool flag;
try
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
this.<set>5__7b = new Set<TSource>(this.comparer);
this.<>7__wrap7d = this.source.GetEnumerator();
this.<>1__state = 1;
goto Label_0092;
case 2:
this.<>1__state = 1;
goto Label_0092;
default:
goto Label_00A5;
}
Label_0050:
this.<element>5__7c = this.<>7__wrap7d.Current;
if (this.<set>5__7b.Add(this.<element>5__7c))
{
this.<>2__current = this.<element>5__7c;
this.<>1__state = 2;
return true;
}
Label_0092:
if (this.<>7__wrap7d.MoveNext())
{
goto Label_0050;
}
this.<>m__Finally7e();
Label_00A5:
flag = false;
}
fault
{
this.System.IDisposable.Dispose();
}
return flag;
}
Есть ли причина, по которой Microsoft должна писать так?
И что означает синтаксис < > в строках типа:
switch (this.<>1__state)
Я никогда не видел, чтобы это было написано перед переменной, только после.
MSIL по-прежнему является действительным кодом 2.x, а имена < > , которые вы видите, автоматически генерируются компиляторами С# 3.x.
Например:
public void AttachEvents()
{
_ctl.Click += (sender,e) => MessageBox.Show( "Hello!" );
}
Переводит на что-то вроде:
public void AttachEvents()
{
_ctl.Click += new EventHandler( <>b_1 );
}
private void <>b_1( object sender, EventArgs e )
{
MessageBox.Show( "Hello!" );
}
Следует также отметить, что причина, по которой вы видите это в Reflector, заключается в том, что оптимизация .NET 3.5 не включена. Перейдите в Вид | Параметры и измените Оптимизация на .NET 3.5, и он лучше выполнит перевод сгенерированных идентификаторов обратно в их выражения lamda.
Вы видите внутренние кишки <конечных машин которые компилятор С# испускает от вашего имени, когда он обрабатывает итераторы.
У Jon Skeet есть отличные статьи (Детали реализации блока итератора и Итераторы, итераторные блоки и конвейеры данных) по этому вопросу. См. Также главу 6 его .
Ранее было сообщение SO по этому вопросу.
И, наконец, Microsoft Research имеет хорошую статью по этому вопросу.
Прочитайте, пока ваше сердце не будет удовлетворено.
Идентификаторы, начинающиеся с < > , не являются допустимыми идентификаторами С#, поэтому я подозреваю, что они используют их для манипулирования именами без страха конфликта, поскольку ни один идентификатор кода С# не может быть таким же.
Что касается того, почему это трудно читать, я подозреваю, что это больше, чем просто его сгенерировать.
Это код, который автоматически генерируется при использовании iterators. < > используется для обеспечения отсутствия коллизий, а также для предотвращения доступа к классам генератора-компилятора непосредственно в вашем коде.
Для получения дополнительной информации см. следующее:
Это типы, которые были автоматически сгенерированы компилятором из методы итератора.
Компилятор будет делать то же самое с вашими итераторами. Например, напишите что-нибудь подобное, а затем взгляните на фактический сгенерированный код в Reflector:
public IEnumerable<int> GetRandom()
{
Random rng = new Random();
while (true)
{
yield return rng.Next();
}
}
Это конечный автомат, который автоматически генерируется из итератора, например:
static IEnumerable<Func<KeyValuePair<int, int>>> FunnyMethod() {
for (var i = 0; i < 10; i++) {
var localVar = i;
yield return () => new KeyValuePair(localVar, i);
}
}
Этот метод вернет 10 для всех значений.
Компилятор преобразует эти методы в конечные машины, которые сохраняют свое состояние в поле <>1__state
и вызывают каждую часть итератора для другого значения поля.
Часть <>
является частью сгенерированного имени поля и выбрана так, чтобы не конфликты ни с чем.
Вы должны понять, что делает Reflector. Он не возвращает исходный код. Это не то, что написал разработчик в MS.:) Он принимает промежуточный язык (IL) и систематически преобразует его обратно в С# (или VB.NET). При этом он должен придумать подход. Как вы знаете, существует много способов скинуть кошку в код, который в конечном итоге приведет к тому же ИЛ. Отражатель должен выбрать способ переместить обратно от ИЛ на язык более высокого уровня и использовать этот способ каждый раз.
(Исправлено за комментарий, спасибо.)