1

Проблема такая - когда дебажишь что-то с помощью Console.WriteLine, хочется просто и быстро узнать значения всех аргументов. Думал сделать так

void Main()
{
int i = 5;
string g = "test";

MassConsoleWriteLine(i,j); }

void MassConsoleWriteLine(object[] params) { string s = ""; foreach(var k in params) { s+= nameof(k) + " is " + k + ", "; } Console.WriteLine(k); }

Ожидаемый результат

i is 5, g is test

Оно не работает - в случае foreach nameof выдает имя внутренней переменной цикла, т.е. k, а в случае for код не компилируется, ибо params[index] не имеет имени.

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

  • 1
    Не уверен, что есть нормальный механизм, кроме передавать туда прямо nameof https://stackoverflow.com/questions/16363753/get-instance-name-c-sharp – CrazyElf Oct 29 '20 at 15:58
  • 5
    пользуйтесь отладкой, не изобретайте колесо. – tym32167 Oct 29 '20 at 15:59
  • Показанный код не компилируется. – aepot Oct 29 '20 at 23:46
  • @aepot о чем я в начале и написал в посте - Оно не работает - в случае foreach nameof выдает имя внутренней переменной цикла, т.е. k, а в случае for код не компилируется, ибо params[index] не имеет имени. – OweAgain Nov 02 '20 at 10:56
  • @aepot Да, я таким тоже страдал, это нужно что бы "дамп" сделать с локальными переменными. Ваш пример, для "частного" случая, и если "подложены" исходники. Ответ - такое можно сделать через анализ IL-кода (тогда отпадает проблема с исходниками, но много мороки с IL). Если не приложен pdb-файл - то можно получить "номера" локальных переменных, которые переданы в ф-цию. Есми приложен - то из pdb файла можно узнать имена локальных переменных. Если есть и pdb и исходники - то можно и таким способом, миинуя IL. – nick_n_a Nov 02 '20 at 12:29
  • @nick_n_a комментарий не туда попал?) – aepot Nov 02 '20 at 12:56
  • @aepot я думаю нет смысла оспаривать ответ, т.к. лучше я за короткое время ненапишу. Возможно у кого-то валяется решение через IL, но маловероятно. – nick_n_a Nov 02 '20 at 13:16
  • @nick_n_a это не рабочее решение, а учебный пример. К тому же весьма специфичный. Я ответ написал просто, потому что знаю как добиться желаемого автором результата. На пуленепробиваемость этот код даже близко не претендует. Более того, очевидео, что без наличия исходников он даже работать не будет. – aepot Nov 02 '20 at 13:19

1 Answers1

4

Вообще это странное занятие, то что вы делаете. Есть отладчик, он вам всё покажет. Но если очень хочется, то почему бы и нет. Хотя-бы для развлечения.

class Program
{
    static void Main()
    {
        int i = 5;
        string j = "test";
    MassConsoleWriteLine(i, j);

    Console.ReadKey();
}

static void MassConsoleWriteLine(params object[] parameters)
{
    // берем стек вызовов и фрейм номер 1 из него, это будет как раз вызывающая строка кода
    StackFrame frame = new StackTrace(true).GetFrame(1);
    // достаем текст этой строки из файла с C# кодом
    string codeLine = File.ReadAllLines(frame.GetFileName())[frame.GetFileLineNumber() - 1].Trim();
    // достаем имена переменных из строки кода
    // я не силен в регулярках, возможно можно сделать красивее
    string[] vars = Regex.Match(codeLine, @"\((.+?)\)").Groups[1].Value.Split(',').Select(x => x.Trim()).ToArray();

    // формируем вывод
    List<string> output = new List<string>();
    for (int i = 0; i < parameters.Length; i++)
    {
        output.Add($"{vars[i]} is {parameters[i]}");
    }

    // выводим
    Console.WriteLine(string.Join(", ", output));
}

}

Вывод в консоль

i is 5, j is test

Здесь много условностей и ограничений, и при изменении условий использования этого кода потребуются доработки. Но на вашем примере оно работает исправно.

aepot
  • 49,560
  • 1
    Как-то так должно быть поуниверсальнее: MassConsoleWriteLine\((?:(\w+),?)*\) потом Groups[1].Captures, правда, с методами по-прежнему не работает. Ну и в случае 2 и более вызовов в одной строке тоже получится фигня. – Qwertiy Nov 02 '20 at 12:30
  • @Qwertiy ну я не претендую на анализатор кода. :) Если попытаться учесть все варианты, можно написать C# парсер, то есть тот самый велосипед. Поэтому ограничусь примитивным решением. – aepot Nov 02 '20 at 12:32
  • Я считал, моё тоже довольно примитивное))) – Qwertiy Nov 02 '20 at 12:47
  • @Qwertiy не могу заставить работать паттерн из вашего первого комментария. Ни в коде, не на regex101. – aepot Nov 02 '20 at 12:53
  • 1
    Я про пробелы забыл. Вот, так мэтчится: MassConsoleWriteLine\s*\(\s*(?:(\w+)\s*,?\s*)*\) – Qwertiy Nov 02 '20 at 13:31