You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求低侵入性方法执行日志类库:仅需添加Decorator/Attribute

兄弟,完全有这种低侵入性的方案!我之前也踩过侵入性强的日志类库的坑——要么得改一堆业务代码,要么耦合度高到后期维护头疼。用Attribute+AOP的思路完美匹配你的需求,只需要给目标方法加个特性,就能自动记录方法执行信息,完全不碰业务逻辑本身。

下面给你两种方向的解决方案,按需选就行:

一、现成类库(省心省力,零侵入)

1. PostSharp

这是老牌的.NET AOP框架,用特性就能实现方法拦截,简直为你的需求量身定做。你只需要定义一个继承自OnMethodBoundaryAspect的特性,实现OnEntry(方法进入)、OnExit(方法退出)等钩子方法,然后给需要监控的方法贴个标签就行。

示例代码:

using PostSharp.Aspects;

[Serializable]
public class MethodLoggingAttribute : OnMethodBoundaryAspect
{
    // 方法开始执行时触发
    public override void OnEntry(MethodExecutionArgs args)
    {
        var paramStr = string.Join(", ", args.Arguments.Select(a => a?.ToString() ?? "null"));
        Console.WriteLine($"[日志] 方法 {args.Method.Name} 开始执行,参数:{paramStr}");
    }

    // 方法执行完成时触发
    public override void OnExit(MethodExecutionArgs args)
    {
        Console.WriteLine($"[日志] 方法 {args.Method.Name} 执行完成,返回值:{args.ReturnValue}");
    }

    // 方法抛出异常时触发
    public override void OnException(MethodExecutionArgs args)
    {
        Console.WriteLine($"[日志] 方法 {args.Method.Name} 抛出异常:{args.Exception.Message}");
    }
}

internal class Calculator
{
    // 只需要加这个特性就搞定!
    [MethodLogging]
    public static int Add(int a, int b)
    {
        return a + b;
    }
}

PostSharp免费版就能覆盖基础的日志需求,付费版有更多高级功能(比如性能监控、事务管理),看你项目规模选就行。

2. Fody + MethodDecorator.Fody

Fody是通过编译时IL织入实现AOP的工具,没有运行时代理的性能损耗,非常轻量化。MethodDecorator.Fody是它的一个专门做方法拦截的插件,用法同样简单到离谱:

  1. 先安装NuGet包:MethodDecorator.Fody
  2. 定义你的拦截特性:
using System.Reflection;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CustomInterceptorAttribute : Attribute
{
    // 方法进入时调用
    public void OnEntry(object instance, MethodBase method, object[] args)
    {
        var paramStr = string.Join(", ", args.Select(a => a?.ToString() ?? "null"));
        Console.WriteLine($"[拦截] 进入方法:{method.Name},参数:{paramStr}");
    }

    // 方法退出时调用(含返回值)
    public void OnExit(object instance, MethodBase method, object[] args, object returnValue)
    {
        Console.WriteLine($"[拦截] 退出方法:{method.Name},返回值:{returnValue}");
    }

    // 方法抛出异常时调用
    public void OnException(object instance, MethodBase method, object[] args, Exception exception)
    {
        Console.WriteLine($"[拦截] 方法 {method.Name} 异常:{exception.Message}");
    }
}

internal class Calculator
{
    // 同样只需要加这个特性
    [CustomInterceptor]
    public static int Add(int a, int b)
    {
        return a + b;
    }
}

Fody是编译阶段修改IL,运行时完全和原生代码一样,性能拉满,而且完全符合你“只加Attribute”的要求。

二、自己实现轻量版(无第三方依赖,灵活可控)

如果你不想依赖任何第三方库,用.NET自带的DispatchProxy就能实现动态代理(注意:默认只支持实例方法,静态方法需要额外处理)。

步骤如下:

  1. 先定义标记用的特性:
[AttributeUsage(AttributeTargets.Method)]
public class CustomInterceptorAttribute : Attribute
{
    // 空特性,只做标记用
}
  1. 实现代理类,处理拦截逻辑:
using System.Reflection;
using System.Reflection.DispatchProxy;

public class LoggingProxy<T> : DispatchProxy
{
    private T _targetInstance;

    // 核心拦截逻辑
    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        var hasInterceptor = targetMethod.GetCustomAttribute<CustomInterceptorAttribute>() != null;
        if (hasInterceptor)
        {
            var paramStr = string.Join(", ", args.Select(a => a?.ToString() ?? "null"));
            Console.WriteLine($"[自定义拦截] 方法 {targetMethod.Name} 开始执行,参数:{paramStr}");
        }

        object result = null;
        try
        {
            // 执行原方法
            result = targetMethod.Invoke(_targetInstance, args);
            
            if (hasInterceptor)
            {
                Console.WriteLine($"[自定义拦截] 方法 {targetMethod.Name} 执行完成,返回值:{result}");
            }
            return result;
        }
        catch (Exception ex)
        {
            if (hasInterceptor)
            {
                var realEx = ex.InnerException ?? ex;
                Console.WriteLine($"[自定义拦截] 方法 {targetMethod.Name} 抛出异常:{realEx.Message}");
            }
            throw;
        }
    }

    // 创建代理实例的工厂方法
    public static T Create(T target)
    {
        var proxy = Create<T, LoggingProxy<T>>();
        ((LoggingProxy<T>)proxy)._targetInstance = target;
        return (T)proxy;
    }
}
  1. 使用方式(把静态方法改成实例方法即可):
internal class Calculator
{
    [CustomInterceptor]
    public int Add(int a, int b)
    {
        return a + b;
    }
}

// 测试代码
var calculator = LoggingProxy<Calculator>.Create(new Calculator());
var sum = calculator.Add(5, 7);

如果一定要支持静态方法,可以用Reflection.Emit生成动态类或者结合Roslyn编译,不过相对复杂一些,上面的实例方案足够覆盖绝大多数业务场景了。


内容的提问来源于stack exchange,提问作者Juan Simon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:55:08