我可以在C#中更改当前的堆栈跟踪吗?

Max*_*kov 8 c# mono unity-game-engine

简而言之,我需要修改C#中的当前堆栈跟踪,因此我调用的方法(我无法修改)会认为是其他人调用它.

现在,给出一个关于为什么我需要做这么可怕的黑客攻击的背景.

在Unity3d中,Debug.Log在开发人员控制台中创建一个新记录.双击它时,它会打开IDE以显示负责该记录的确切文件和行.但是,由于各种原因(在生产中禁用调试,使其在其他线程中可用)我创建了一个包装类Print,而不是UnityEngine.Debug.

但是使用包装器,现在当开发人员在控制台中单击日志记录时,它会Print被打开,而不是Print.Log被调用的实际位置.因为Debug.Log无论错误消息或上下文对象如何,我都认为它使用调用堆栈来识别要打开的文件.不用说,我想解决这个问题.

Jer*_*vel 4

我不相信这是可能的。查看源代码Environment.StackTrace和后续GetStackTrace()调用,我们可以看到它每次调用时都会创建堆栈跟踪。由于似乎没有任何东西可以注入来改变它的一些工作,所以我认为可以安全地得出这样的结论:如果不修改堆栈跟踪的调用方式,就无法更改它。

如果您有可能这样做,您可以使用类似的方法来检索当前的堆栈跟踪并使用反射来更改最新的StackFrame字段method以模仿您所追求的内容。

void Main()
{
    DoSomething();
}

void DoSomething(){
    Console.WriteLine (Environment.StackTrace); // Last frame: at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)

    var frames = new StackTrace().GetFrames();
    var lastframe = frames[0]; // last frame: DoSomething at offset 100 in file:line:column <filename unknown>:0:0
    var methodField = lastframe.GetType().GetField("method", BindingFlags.Instance | BindingFlags.NonPublic);
    var redirectedMethod = typeof(Redirect).GetMethod("RedirectToMethod", BindingFlags.Instance | BindingFlags.Public);
    methodField.SetValue(lastframe, redirectedMethod);
    Console.WriteLine (frames); // last frame: RedirectToMethod at offset 100 in file:line:column <filename unknown>:0:0
    Console.WriteLine (Environment.StackTrace); // last frame: at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
}

public class Redirect {
    public void RedirectToMethod() { }
}
Run Code Online (Sandbox Code Playgroud)

但再次强调:这非常脆弱,不适用于您当前的情况。您尝试做的事情相当奇特,应该完全避免。

至于实际的解决方案:恐怕我没有任何使用 Unity 的经验,所以我只能用 google 搜索,但您可能会对这个线程感兴趣。我在这里提到了 .NET 源代码,但是您当然可以在 Mono 源代码中找到非常相似的代码。