Мне сложно отслеживать проблему блокировки, поэтому я хотел бы зарегистрировать каждую запись вызова метода и выйти. Я делал это раньше с С++, не добавляя код ко всем методам. Возможно ли это с С#?
Как добавить Trace() для каждого вызова метода в С#?
Ответ 1
Вероятно, лучшим вариантом будет использование структуры AOP (аспектно-ориентированного программирования) для автоматического вызова кода трассировки до и после выполнения метода. Популярным выбором для AOP и .NET является PostSharp.
Ответ 2
Профилировщик отлично подходит для просмотра вашего исполняемого кода во время разработки, но если вы ищете возможность делать пользовательские трассы в процессе производства, то, как упоминал Денис Г., PostSharp - идеальный инструмент: вам не нужно менять весь свой код, и вы можете легко включить его/выключить.
Он также легко настраивается за несколько минут, и Gaël Fraiteur, создатель PostSharp даже имеет видео, которое показывает вам, как легко добавлять трассировку в существующее приложение.
Вы найдете примеры и руководства в разделе .
Ответ 3
Если ваша основная цель состоит в том, чтобы регистрировать точки входа/выхода из функции и случайную информацию между ними, у меня были хорошие результаты с помощью объекта Одноразовый, где конструктор отслеживает запись функции и Dispose() отслеживает выход. Это позволяет вызывающему коду просто обернуть каждый код метода внутри одного с помощью оператора. Также предлагаются методы для произвольных журналов между ними. Вот полный класс отслеживания событий С# ETW, а также оболочка ввода/вывода функций:
using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyExample
{
// This class traces function entry/exit
// Constructor is used to automatically log function entry.
// Dispose is used to automatically log function exit.
// use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing
public class FnTraceWrap : IDisposable
{
string methodName;
string className;
private bool _disposed = false;
public FnTraceWrap()
{
StackFrame frame;
MethodBase method;
frame = new StackFrame(1);
method = frame.GetMethod();
this.methodName = method.Name;
this.className = method.DeclaringType.Name;
MyEventSourceClass.Log.TraceEnter(this.className, this.methodName);
}
public void TraceMessage(string format, params object[] args)
{
string message = String.Format(format, args);
MyEventSourceClass.Log.TraceMessage(message);
}
public void Dispose()
{
if (!this._disposed)
{
this._disposed = true;
MyEventSourceClass.Log.TraceExit(this.className, this.methodName);
}
}
}
[EventSource(Name = "MyEventSource")]
sealed class MyEventSourceClass : EventSource
{
// Global singleton instance
public static MyEventSourceClass Log = new MyEventSourceClass();
private MyEventSourceClass()
{
}
[Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceMessage(string message)
{
WriteEvent(1, message);
}
[Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceCodeLine([CallerFilePath] string filePath = "",
[CallerLineNumber] int line = 0,
[CallerMemberName] string memberName = "", string message = "")
{
WriteEvent(2, filePath, line, memberName, message);
}
// Function-level entry and exit tracing
[Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)]
public void TraceEnter(string className, string methodName)
{
WriteEvent(3, className, methodName);
}
[Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)]
public void TraceExit(string className, string methodName)
{
WriteEvent(4, className, methodName);
}
}
}
Используемый код будет выглядеть примерно так:
public void DoWork(string foo)
{
using (FnTraceWrap fnTrace = new FnTraceWrap())
{
fnTrace.TraceMessage("Doing work on {0}.", foo);
/*
code ...
*/
}
}
Ответ 4
Использовать ANTS Profiler из Red Gate будет вашим лучшим выбором. В противном случае загляните в interceptors в Castle Windsor. Это предполагает, что вы загружаете свои типы через IoC, хотя.
Отражение - это еще один способ, вы можете использовать методы System.Reflection.Emit для "записи" кода в память. Этот код может заменить ваш код метода и выполнить его, но с соответствующим протоколированием. Удачи вам в этом, хотя... Легче было бы использовать платформу с ориентированным ориентиром, например Aspect #.
Ответ 5
Возможно, он ожидает, что проблема блокировки будет приостановлена, сделав дамп памяти и проанализируя стек вызовов на разных потоках. Вы можете использовать DebugDiag или adplus script (в этом случае режим зависания), который поставляется с Инструменты отладки для Windows.
Тесс Феррандес также имеет отличную лабораторную серию об обучении отладке различных проблем с использованием дампов памяти .NET. Я очень рекомендую его.
Ответ 6
Откуда вы знаете, что это происходит? Если это многопоточное приложение, я бы рекомендовал тестировать условие и вызывать System.Diagnostics.Debugger.Break() во время выполнения, когда он обнаружен. Затем просто откройте окно "Нитки" и пройдите через стеки вызовов по каждому соответствующему потоку.
Ответ 7
если у вас есть проблема с блокировкой http://www.codeproject.com/KB/dotnet/Deadlock_Detection.aspx
Ответ 8
Попробуйте jetbrains dottrace - это .NET Performance Profiler. вам не нужно изменять свой код. и это дает вам 10 дней для судебного разбирательства.
Вот учебник для dottrace