Есть ли способ извлечь или сохранить данные из атрибута? - PullRequest
0 голосов
/ 17 марта 2011

Я начинаю работать с атрибутами, и для этого примера код написан с использованием PostSharp 2.0.

То, что я хотел бы сделать, - это метод с атрибутом Stopwatch, или вызывающий метод может получить доступ к прошедшему времени.

В настоящее время я пишу эти коды, используя C # 4.0

Пример кода атрибута:

[Serializable]
public class StopwatchAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        // Create new stopwatch
        Stopwatch stopwatch = new Stopwatch();

        // Begin timing
        stopwatch.Start();

        args.MethodExecutionTag = stopwatch;
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        Stopwatch stopwatch = (Stopwatch)args.MethodExecutionTag;

        // Stop timing
        stopwatch.Stop();

        // Write result
        Debug.WriteLine("Time elapsed: {0} ms", stopwatch.Elapsed);
    }
}

Использование атрибута

[Stopwatch]
public string Search(string LineNo)
{
    // Search for something
    // Is it possible to know how long (from Stopwatch attribute) Search took 
}

public void CallSearch
{
    string x =  Search("xyz");
    // Is it possible to know how long (from Stopwatch attribute) Search took 
}

Я получаю вывод прошедшего времени.

Однако есть ли возможность расширить это, чтобы я мог отправить истекшее время ожидания.

В идеале я хотел бы посмотреть, сколько времени Search взято из CallSearch, но все будет хорошо, если я смогу даже получить результат в Search и затем каким-то образом вернуть его.

В качестве обходного пути я в настоящее время использую "Отверстие в середине" шаблон.

Спасибо

Ответы [ 4 ]

1 голос
/ 17 марта 2011

Ну, переменные в атрибуте перестанут существовать после завершения метода.Для этого вам необходимо оценить журнал или какой-либо другой постоянный источник данных.Вы можете записать данные в статический список или что-то подобное, но вы не можете написать код, который бы рефлексивно исследовал сам атрибут, чтобы определить, как долго длился последний запуск метода с этим атрибутом (если только у класса атрибута нет методапроверяет то же постоянное хранилище).

Атрибут, как вы написали, является просто классом, который используется в CLR особым образом;он проверяет наличие аспектно-ориентированных атрибутов, создает любые из них по мере необходимости и вызывает любые обработчики по мере необходимости.Класс находится только в области видимости, пока он необходим среде выполнения, а если это не так, он GCed.Чтобы работать с атрибутом вне его аспектно-ориентированного назначения, вы работаете с его типом и / или создаете новый его экземпляр с помощью активатора.

Одна вещь;Атрибут может иметь статические свойства.Таким образом, вы можете определить статический экземпляр секундомера и установить его на секундомер, который вы недавно остановили в OnExit.Это позволило бы вам статически определить время последнего выполненного метода, украшенного атрибутом.

1 голос
/ 17 марта 2011

Я считаю, что атрибуты доступны только для чтения и полностью определяются во время компиляции. Вы не можете влиять на атрибуты после компиляции кода. Возможно, вы могли бы сохранить статический словарь (отображение делегатов или MemberInfo на значения времени выполнения), чтобы отслеживать время последнего выполнения каждого метода, помеченного для отслеживания времени его выполнения?

0 голосов
/ 04 февраля 2014

Атрибуты следует использовать только для добавления описаний к классам, свойствам и методам во время разработки, которые затем можно исследовать во время выполнения с помощью отражения.

Я бы не использовал его для хранения бизнес-логики.*

Вот вам замечательная статья для справки.

0 голосов
/ 17 марта 2011

Возможное решение (извините, я не проверял его, но идея должна быть ясна):

[Serializable]
public class StopwatchAttribute : OnMethodBoundaryAspect
{
    [ThreadStatic]
    private static Stopwatch stopwatch = null;

    public override void OnEntry(MethodExecutionArgs args)
    {
        var sw = stopwatch ?? new Stopwatch();
        args.MethodExecutionTag = sw; // Better to move this line before .Start
        sw.Start();
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        var sw = (Stopwatch) args.MethodExecutionTag;
        sw.Stop();
        Debug.WriteLine("Time elapsed: {0} ms", sw.Elapsed);
    }

    public static Stopwatch Measure(Action action)
    {
        var oldStopwatch = stopwatch;
        stopwatch = new Stopwatch();
        try {
            // !!! Btw, you can measure everything right here.
            action.Invoke();
            return stopwatch;
        }
        finally {
            stopwatch = oldStopwatch;
        }
    }
}

Предполагаемое использование:

[Stopwatch]
public string Search(string LineNo)
{
    // Search for something
    // Is it possible to know how long (from Stopwatch attribute) Search took 
}

public void CallSearch
{
    var stopwatch = StopwatchAttribute.Measure(() => {
        string x =  Search("xyz");
    });
    Console.WriteLine("Time elapsed: {0} ms", stopwatch.Elapsed);
}

Итак, как вы видите, использование PostSharp здесь не совсем необходимо. Его можно использовать для регистрации таких моментов времени, но вы должны использовать либо похожий подход, либо свой собственный API доступа к журналу, чтобы получить зарегистрированное время.

...