Почему результат вызова метода неточный или входим в исходный код .Net Framework

Был недавно вопрос по поводу функции Directory.EnumerateFiles(), которая ведёт себя не очень понятно при вызове. Т.е. возвращает не то, что требуется, а совсем иной результат. Впрочем сегодняшняя статья не о ней, а о такой мощной возможности плаформы .Net, как вход в исходный код во время отладки. Думаю, если не большинство, то многие не знают и не догадываются о такой возможности. С января 2008 года компания Microsoft открыла сервер символов, который содержит исходный код большинства библиотек платформы. Данную возможность можно использовать начиная с Visual Studio 2008 SP1, и до текущей - Visual Studio 2012. Я продемонстрирую пример в среде Visual Studio 2010 SP1, для других версий всё почти так же. И так приступим. Проблема в том, что при указании в качестве шаблона, например "*.log" в результаты выборки попадают и файлы с "*.logs". Получается результат не соответствует описанию. Создадим простое консольное приложение с нижеприведённым кодом, чтобы проверить, что там происходит на самом деле.
namespace StepInCode
{
  class Program
  {
    static void Main(string[] args)
    {
      var p = Directory.EnumerateFiles("e:\\temp\\", "*log", SearchOption.TopDirectoryOnly);
    }
  }
}
Дальше заходим в настройки меню Debug (Tools –> Options –> Debugging –> General).
Ставим галочку в чекбокс “Enable .NET Framework source stepping” .
 


При этом "Enable Just My Code" отключится автоматически. Далее идём и настраиваем источник символов.



Хотя тут и настраивать нечего, просто нужно указать директорию где символы будут загружены и сохранены. Если интернет быстрый, то их загрузка (естественно не всех, а только используемых в настоящий момент сборок) во время отладки не займёт много времени. Можно ещё и пойти другим путём. Идём и загрожаем готовые установочные пакеты отсюда.



Ждём пока загрузка завершится.



Запускаем установку пакета.



Выбираем каталог установки.



Ждём завершения.



Установка завершена. Настраиваем источник символов, как показано ниже.



Да, и обязательно галочка "Require source files to exactly match the original version" должна быть снята.



Второй вариант более длинный, поэтому если у Вас быстрый интернет то лучше выбрать первый. Поскольку всё готово, запускаем отладку.



Загружаем нужные символы для сборки. И продвигаемся по вызовам (клавиша F11)



пока не достигаем места вызова нужной нам функции. Видно, что вызывается функция Win API "HANDLE WINAPI FindFirstFile", и судя по документации в ней символ '*' означает местозаполнитель и строки вида:

e:\\temp\\*.log

e:\\temp\\*.logs

попадают под шаблон. Поэтому и возвращается не то, что нам нужно было. Тем самым объясняется странное поведение функции. Как выход, можно сделать так:
namespace StepInCode
{
  class Program
  {
    static void Main(string[] args)
    {
      var files = DirectoryExtender.GetFiles("e:\\temp\\", SearchOption.TopDirectoryOnly);
    }
  }
  public static class DirectoryExtender
  {
    public static IEnumerable<string> GetFiles(string path,
      SearchOption searchOption = SearchOption.TopDirectoryOnly)
    {
      Regex reSearchPattern = new Regex(@".log$");
      return Directory.EnumerateFiles(path, "*", searchOption)
        .Where(file => reSearchPattern.IsMatch(Path.GetExtension(file)));
    }
  }
}
Для входа в исходный код .Net Framework 4.5  с помощью Visual Studio 2012, последовательность шагов аналогична.
MeF Corvi
26.11.2012 1:48
Цитата
Видно, что вызывается функция Win API "HANDLE WINAPI FindFirstFile", и судя по документации в ней символ '*' означает местозаполнител­ь и строки вида:
e:\\temp\\*.log

e:\\temp\\*.log­s
Дело не совсем в этом. Проблема в том, что FindFirstFile работает с именами файлов в устаревшем формате MS-DOS 8.3. Соответственно, имена вида "SomethingName.­someExt" трактуются как "SOMETH~1.SOM", и благополучно попадают под маску "*.SOM". И об этом написано в MSDN http://msdn.microsoft.com/en-us/library/wz42302f.aspx

Ну и регулярное выражение в вашем случае - это черезчур. Проще уж использовать EndsWith.
26.11.2012 10:05
Спасибо за дополнение. Согласен, но как уже было отмечено высше, цель - демонстрация возможности входа в исходный код. Возможность есть уже достаточно давно, но многие и не догадываются об этом, постоянно переспрашивают. С регулярными выражениями тоже переборщил. Настолько тесно с ними работаю, что порой забываю о таких простых и более эффективных вещах, как обычные строковые методы.
Test576
26.11.2012 3:01
А я бы просто в Рефлектор бы зашел...
26.11.2012 10:08
Рефлектор, рефлектором...н­о у возможности прохода по исходному коду есть свои преимущества, которые трудно переоценить.
rush.khaz
26.11.2012 14:50
Получается, что мы получаем в результате абсолютно все исходные файлы библиотек?
26.11.2012 15:40
Нет. Мы получаем символы отладки. Грубо говоря, это то, посредством чего отладчик преобразует (или сопоставляет) скомпилированны­й двоичный код в исходный.
supertoha
26.11.2012 23:09
Спасибо за интересную и познавательную статью, всю жизнь пользуюсь рефлектором и не знал о такой возможности.
slogic
02.04.2013 15:49
продемАнстрирую -> продемОнстрирую
02.04.2013 17:24
Спасибо, исправил.
Andrey
26.03.2014 16:21
Ссылка на сервер символов, указанная в начале данной заметки, не рабочая:

Server Error in '/' Application.

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

Requested URL: /netframework.a­spx
26.03.2014 16:47
Знаю, их просто удалили.