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

C#如何无需为每个类型新增属性即可获取其对应的.cs文件路径

方案1:基于StackTrace + PDB实现(无需修改现有代码)

异常能获取源文件路径的核心是程序集对应的PDB文件中存储了IL指令和源文件位置的映射关系,直接通过StackTrace读取该信息即可,不需要为每个类型新增属性:

using System.Diagnostics;
using System.Reflection;

public static class SourceFileLocator
{
    /// <summary>
    /// 获取指定类型对应的.cs源文件路径
    /// </summary>
    /// <param name="type">目标类型</param>
    /// <returns>源文件绝对路径,无对应PDB时返回null</returns>
    public static string GetCSharpFilePath(Type type)
    {
        // 优先取类型的构造函数,避免接口/抽象类无实现方法的问题
        MethodBase method = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                .FirstOrDefault();
        
        // 无构造函数时取第一个非抽象方法
        method ??= type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
                       .FirstOrDefault(m => !m.IsAbstract);

        if (method == null) return null;

        // 第二个参数设为true表示捕获源文件信息
        StackTrace stackTrace = new StackTrace(method, true);
        StackFrame frame = stackTrace.GetFrame(0);
        
        return frame?.GetFileName();
    }
}

适用场景

  • 环境中存在对应程序集的PDB调试文件(默认Debug、Release发布模式都会生成,仅当手动勾选删除调试信息、使用裁剪/AOT编译时会失效)
  • 支持获取任意非抽象类型的源文件路径
    如果需要批量获取所有实现了指定接口的类型路径,可以扩展如下方法:
using System.Reflection;
using System.Linq;

public static IEnumerable<(Type ImplementType, string FilePath)> GetAllInterfaceImplPaths<TInterface>()
{
    // 可按需替换为目标程序集
    Assembly targetAssembly = Assembly.GetExecutingAssembly();
    
    var implTypes = targetAssembly.GetTypes()
                                  .Where(t => typeof(TInterface).IsAssignableFrom(t) 
                                              && !t.IsInterface 
                                              && !t.IsAbstract);

    foreach (var type in implTypes)
    {
        string path = GetCSharpFilePath(type);
        if (!string.IsNullOrEmpty(path))
        {
            yield return (type, path);
        }
    }
}

方案2:基于源生成器实现(无PDB也可使用,性能更高)

如果需要在无PDB的生产环境使用,且使用C# 9及以上版本,可以通过增量源生成器自动为所有目标类型插入路径属性,不需要手动修改每个类的代码:

  1. 实现一个增量源生成器,扫描项目中所有实现目标接口的类型
  2. 自动为每个匹配的生成分部类代码,插入编译时生成的路径属性:
// 源生成器自动生成的分部类代码示例
public partial class YourTargetType
{
    public string SourceFilePath { get; } = GetCallerFilePath();
    
    private static string GetCallerFilePath([System.Runtime.CompilerServices.CallerFilePath] string path = default)
        => path;
}

适用场景

  • 目标类型均为当前项目可编译的代码,不支持第三方程序集类型
  • 编译时完成路径注入,运行时无性能损耗,不需要依赖PDB文件

说明

你之前尝试的基类中加[CallerFilePath]无法获取子类路径的问题,是因为该特性是编译时替换属性,基类的代码编译时就被替换为基类的源文件路径,子类继承时不会重新计算,因此无法实现需求。

内容的提问来源于stack exchange,提问作者Xavier Peña

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:42:01