Как получить имя текущего класса в C# (собственное имя класса)?
Получение имени вызывающего класса через StackTrace
Самый простой и распространённый способ — использовать класс StackTrace из пространства имён System.Diagnostics. Он позволяет получить информацию о стеке вызовов и узнать, какой метод и класс вызвали текущий метод.
Вот как это работает для вашего логгера:
using System;
using System.Diagnostics;
public static class Logger
{
public static void Log(string message)
{
// Получаем стек вызовов
StackTrace stackTrace = new StackTrace();
// Фрейм с индексом 1 — это тот, кто вызвал Log (индекс 0 — сам Log)
StackFrame callingFrame = stackTrace.GetFrame(1);
// Получаем метод, который вызвал Log
var callingMethod = callingFrame.GetMethod();
// Получаем тип (класс), которому принадлежит этот метод
string className = callingMethod.DeclaringType.Name;
Console.WriteLine($"[{className}] {message}");
}
}
public class MyClass
{
public void DoSomething()
{
Logger.Log("Начало операции"); // Выведет: [MyClass] Начало операции
}
}
public class AnotherClass
{
public void Process()
{
Logger.Log("Обработка данных"); // Выведет: [AnotherClass] Обработка данных
}
}
Важные моменты:
- Индекс фрейма:
GetFrame(0)— это сам методLog,GetFrame(1)— вызывающий метод,GetFrame(2)— метод, вызвавший вызывающий и т.д. - Производительность: Создание
StackTrace— относительно дорогая операция. Для часто вызываемых методов (например, в цикле) это может быть проблемой. - Оптимизации JIT: В релизной сборке компилятор может встроить (inline) метод
Log, и стек вызовов исказится. Чтобы этого избежать, можно добавить атрибут[MethodImpl(MethodImplOptions.NoInlining)]к методуLog.
Оптимизированная версия с атрибутом:
using System.Runtime.CompilerServices;
public static class Logger
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Log(string message)
{
StackTrace stackTrace = new StackTrace();
StackFrame callingFrame = stackTrace.GetFrame(1);
string className = callingFrame.GetMethod().DeclaringType.Name;
Console.WriteLine($"[{className}] {message}");
}
}
Альтернатива через CallerMemberName (если нужно только имя метода):
Если вам нужно имя вызывающего метода (а не класса), можно использовать атрибут [CallerMemberName] — он работает без рефлексии и быстрее:
public static void Log(string message, [CallerMemberName] string callerName = "")
{
Console.WriteLine($"[{callerName}] {message}");
}
Но для получения имени класса этот атрибут не подходит — он передаёт только имя метода.
В вашем случае рекомендую использовать StackTrace с индексом 1 и атрибутом NoInlining — это надёжное и понятное решение.
Использование CallerFilePath и парсинг имени класса
Ещё один подход, который может быть полезен, если вы не хотите использовать StackTrace (например, из-за производительности или особенностей JIT). Компилятор C# предоставляет атрибуты CallerFilePath, CallerLineNumber и CallerMemberName, которые подставляются на этапе компиляции без накладных расходов во время выполнения.
Хотя CallerFilePath передаёт полный путь к файлу, а не имя класса, вы можете извлечь имя класса из имени файла, если соблюдаете соглашение: файл называется так же, как класс (например, MyClass.cs → класс MyClass).
using System;
using System.IO;
public static class Logger
{
public static void Log(string message, [CallerFilePath] string filePath = "")
{
// Извлекаем имя файла без расширения
string fileName = Path.GetFileNameWithoutExtension(filePath);
Console.WriteLine($"[{fileName}] {message}");
}
}
public class MyClass
{
public void DoSomething()
{
Logger.Log("Начало операции"); // Выведет: [MyClass] Начало операции
}
}
Плюсы и минусы:
- + Очень быстро — не использует рефлексию и не создаёт стек вызовов.
- + Не подвержено проблемам с JIT-встраиванием.
- - Работает только если имя файла совпадает с именем класса (что обычно верно, но не гарантируется).
- - Не сработает для частичных классов, вложенных классов или если файл переименован.
Этот метод хорошо подходит для простых логгеров или отладочной печати, где важна производительность, а точность не критична.
Ответов пока нет.
Войдите чтобы оставить ответ