Как реализовать общие функции для различных методов диагностики c в. NET Core? - PullRequest
0 голосов
/ 08 июля 2020

У меня есть приложение. NET Core 3.1. В этом приложении у меня есть следующие стандартные методы:

public List<Item> GetAll()
{
    // retrieve all items from the database
}

public async Task<List<Item>> GetAllAsync()
{
    // retrieve all items from the database
}

public List<Item> GetAll(bool includeDeleted, DateTime? after)
{
  // retrieve all items based on the query details passed in as parameters.
}

public Item Get(int id)
{
    // retrieve a specific item from the database
}

public async Task<Item> GetAsync(int id)
{
    // retrieve a specific item from the database.
    // The id parameter is needed
}

public void DoSomething()
{
  // No parameters are needed
}

В этих и других методах моего проекта у меня есть лот шаблонного кода. Этот шаблонный код в основном 1) регистрирует производительность и 2) обеспечивает общую c обработку ошибок. В настоящее время шаблонный код в основном выглядит так:

var log = new Log("<Friendly Method Name Goes Here">);

Stopwatch stopwatch = null;
try 
{
  stopwatch = Stopwatch.StartNew();
    
  // method code
  log.Result = null, Item, or List<Item> depending on which method is called

  stopwatch.Stop();
  log.ElapsedTicks = stopwatch.ElapsedTicks;
  log.Success = true;
}
catch (Exception) 
{
  log.Success = false;
} 

Вместо того, чтобы копировать приведенное выше и помещать его в каждый метод, похоже, что я должен иметь возможность передать «реальную работу», которую необходимо выполнить, в один метод и заполнить что-то вроде объекта Result, который включает в себя реальный результат и метаданные (т.е. производительность, понятное имя метода, et c.) Это привело меня к тому, что я вставил что-то вроде следующего в каждый метод:

var result = new Result();
Func<Task> task = async (result) =>
{
  var outcome = // get item(s) from database
  result.Result = outcome;
  await Task.CompletedTask;
};

Затем я собирался поместить свой шаблонный код в общий метод и передать task . Однако быстро возникли некоторые проблемы:

  1. Как передать ноль, один или несколько параметров?
  2. Я могу записать метаданные в объект Result в Func. Однако как мне обновить свойства объекта Result в общем методе (то, что регистрирует производительность, и т. Д. c.)?

Я не могу сказать, м не замечаю что-то в C# или если у меня архитектурная проблема Мне кажется, что иметь общий код, который обрабатывает основные вещи (например, измеряет производительность), но достаточно гибкий, чтобы настраивать на более детальном уровне, является разумным. Есть ли способ сделать это в C#? Если да, то как?

Спасибо!

1 Ответ

0 голосов
/ 08 июля 2020

Я бы так поступил, это не самый эффективный способ, но довольно простой. Ваши параметры, которые вы используете, становятся замыканиями в стандартном контексте, не нужно беспокоиться об этом, если вы не делаете тяжелую работу с памятью. Первый класс определяет стандартные операции, вы получаете имя метода и исходный файл, который автоматически вызывает вас для ведения журнала. Второй класс реализует шаблонный контекст. Поддерживает перегрузки syn c и asyn c, вам может потребоваться добавить еще 2 перегрузки без типов возврата для методов void, но это легко. Вы можете расширить определение Fun c <> дополнительными типами и передать что-то из шаблона в такие методы, как фабрика контекста БД или что-то в этом роде.

namespace Test
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;

    public static class Boilerplate
    {
        // Boilerplater (tm) for async methods
        public static async Task<T> Run<T>(Func<Task<T>> operation, [CallerMemberName] string method = null, [CallerFilePath] string module = null)
        {
            // some boilerplate init
            Console.WriteLine($"Method {method} started.");

            var result = await operation.Invoke();

            // some wrapup
            Console.WriteLine($"Method {method} ended.");

            return result;
        }

        // Boilerplater (tm) for sync methods
        public static T Run<T>(Func<T> operation, [CallerMemberName] string method = null, [CallerFilePath] string module = null)
        {
            // some boilerplate init
            Console.WriteLine($"Method {method} started.");

            var result = operation.Invoke();

            // some wrapup
            Console.WriteLine($"Method {method} ended.");

            return result;
        }
    }
    /// <summary>
    /// Example app
    /// </summary>
    public class MyApp
    {
        public async Task<List<string>> GetAllAsync(string input) 
            => await Boilerplate.Run(async () =>
            {
                // do something async in the boilerplate context
                var result = new List<string>();
                await Task.Delay(1);
                result.Add(input);
                return result;
            });

        public List<string> GetAll(string input) 
            => Boilerplate.Run(() =>
            {
                // do something non-async in the boilerplate context
                var result = new List<string>();
                result.Add(input);
                return result;
            });
    }
}

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

...