有没有办法告诉在c#中调用函数的方法的参数?

有没有办法告诉在c#中调用函数的方法的参数?,c#,.net,reflection,stack-trace,C#,.net,Reflection,Stack Trace,我正在为我的c#应用程序开发一种免提日志机制 以下是我希望它看起来的样子: 函数a(arg1,arg2,arg3…)调用函数b(arg4,arg5,arg6…),后者依次调用log(),后者无法检测堆栈跟踪(这可以通过环境.stacktrace)以及每个函数使用的值(例如a和b)在stacktrace中调用 我希望它在调试和发布模式下工作(或者,至少在调试模式下) 这可以在.net中实现吗?显然不可能: 调用b时,a的arg1使用的堆栈中的空间(IL堆栈,因此可能从未放入堆栈,但在调用时已注册)

我正在为我的c#应用程序开发一种免提日志机制

以下是我希望它看起来的样子:

函数
a(arg1,arg2,arg3…)
调用函数
b(arg4,arg5,arg6…)
,后者依次调用
log()
,后者无法检测堆栈跟踪(这可以通过
环境.stacktrace
)以及每个函数使用的值(例如
a
b
)在stacktrace中调用

我希望它在调试和发布模式下工作(或者,至少在调试模式下)

这可以在.net中实现吗?

显然不可能:

调用
b
时,a的
arg1
使用的堆栈中的空间(IL堆栈,因此可能从未放入堆栈,但在调用时已注册)不能保证仍被
arg1
使用

根据扩展,如果
arg1
是引用类型,那么如果调用
b
后没有使用它,则不能保证它引用的对象没有被垃圾收集

编辑

更详细一点,因为你的评论表明你并没有在这方面摸索,并且仍然认为这应该是可能的

抖动使用的调用约定在任何相关标准的规范中都没有指定,这使实现者可以自由地进行改进。32位和64位版本以及不同的版本之间确实存在差异

然而,MS people的文章表明,所使用的公约与公约类似。在您对
a
的调用中,
arg1
将被放入ECX寄存器*,而
arg2
将被放入EDX寄存器(我通过假设32位x86进行简化,使用amd64注册了更多参数),这是代码运行的核心
arg3
将被推送到堆栈上,并且确实存在于内存中

请注意,此时没有
arg1
arg2
存在的内存位置,它们只在CPU寄存器中

在执行方法本身的过程中,根据需要使用寄存器和内存。然后调用
b

现在,如果
a
需要
arg1
arg2
它必须在调用
b
之前按下该按钮。但如果它不这样做,那么它就不会这样做——甚至可能会重新安排工作以减少这种需求。相反,到目前为止,这些寄存器可能已经被用于其他用途-抖动并不愚蠢,因此如果它需要一个寄存器或堆栈上的插槽,并且有一个在方法的其余部分未使用,它将重用该空间。(就此而言,在上述级别上,C#编译器将重用IL生成的虚拟堆栈中使用的插槽)

因此,当调用
b
时,
arg4
被放置在寄存器ECX中,
arg5
被放入EDX中,
arg6
被推到堆栈上。在这一点上,
arg1
arg2
不存在,你再也找不到它们是什么了,就像你在一本书被回收并变成厕纸后可以阅读一样

(有趣的是,一个方法调用另一个在相同位置具有相同参数的方法是很常见的,在这种情况下,ECX和EDX可以单独使用)

然后,
b
返回,将其返回值放入EAX寄存器或EDX:EAX对或内存中,EAX指向它,具体取决于大小,
a
在将其返回放入该寄存器之前做更多的工作,依此类推

现在,这是假设没有进行任何优化。事实上,
b
可能根本没有被调用,而是它的代码是内联的。在这种情况下,无论是寄存器中的值还是堆栈上的值——以及在后一种情况下,它们在堆栈上的值,都不再与
b
的签名有关,也不再与
a
执行期间相关值的位置有关,而在另一个对
b
的“调用”的情况下,情况会有所不同,甚至在从
a
b
的另一个“调用”的情况下,因为
a
的整个调用(包括对
b
的调用)可能在一种情况下内联,而在另一种情况下没有内联,并且在另一种情况下内联方式不同。例如,如果代码< > ARG4</代码>直接从另一个调用返回的值,它可以在EAX登记器中,而Ag5在ECX中,因为它与代码> Ag1 相同,并且Alg6在代码<> A< < /C> >中使用的中途的某个中途。

另一种可能性是,对
b
的调用是一个被消除的尾部调用:因为对
b
的调用也将由
a
立即返回其返回值(或其他一些可能性),然后,
a
使用的值将被替换到位,而不是推到堆栈中,并且返回地址发生了变化,因此从
b
返回的方法跳回调用
a
的方法,跳过了一些工作(并减少了内存使用,使一些会溢出堆栈的函数式方法能够正常工作)。在这种情况下,在调用
b
的过程中,
a
的参数很可能完全消失,即使是堆栈上的参数

最后一种情况是否应该被视为一种优化,这是一个高度争议的问题;有些语言在很大程度上依赖于它的执行,因为它们提供了良好的性能,而如果它们完全正常工作(而不是溢出堆栈),它们的性能就会非常糟糕

可以有各种各样的其他优化。如果是.NET团队还是Mono团队,应该有各种各样的优化
IEnumerable<T> RepeatedlyInvoke(Func<T> factory, int count)
{
  if(count < 0)
    throw new ArgumentOutOfRangeException();
  while(count-- != 0)
    yield return factory();
}