Is there any way in C# to pass a random method as a parameter?
在C#中有任何方法可以将随机方法作为参数传递吗?
To explain my question:
解释我的问题:
I want to write a simple Logger-Tool that reports the entering and leaving of a method with the passed arguments an the class and method name:
我想编写一个简单的Logger-Tool,它使用传递的参数报告方法的进入和离开,以及类和方法名称:
The log file I'm aiming at:
我的目标是:
ENTERING: ClassOfDoom::MethodOfDoom( arg1={1} [int], arg2={true} [bool] )
LEAVING: ClassOfDoom::MethodOfDoom RETURNING 1 [int]
The code I have in mind:
我想到的代码:
class ClassOfDoom {
// Remeber: MethodOfDoom is a _random_ method with _random_ arguments
public int MethodOfDoom(int arg1, bool arg2) {
Log.Entering(this, this.MethodOfDoom, arg1, arg2);
...
return Log.Returing(this, this.MethodOfDoom, 1);
}
}
Is there a way to achieve this? Or isn't C# as flexible as that?
有没有办法实现这个目标?或者C#不是那么灵活吗?
Thanks in advance!
提前致谢!
5 个解决方案
#1
You can make your logging function take a MethodBase
argument and use MethodBase.GetCurrentMethod to pass the current method info as an argument.
您可以使您的日志记录函数采用MethodBase参数并使用MethodBase.GetCurrentMethod将当前方法信息作为参数传递。
Then, in the logger, you could check its properties Name
and DeclaringType
to get the method information. Also, passing parameters is easy by declaring a params object[] args
parameter in the logging function:
然后,在记录器中,您可以检查其属性Name和DeclaringType以获取方法信息。此外,通过在日志记录函数中声明params object [] args参数,可以轻松传递参数:
public static void Entering(object obj, MethodBase methodInfo,
params object[] args) {
Console.WriteLine("ENTERING {0}:{1}", methodInfo.DeclaringType.Name,
methodInfo.Name);
...
}
#2
I'm not sure I entirely understand your question, but if you are trying to make a call to Log.Entering and Log.Returning inside an arbitrary (random) method and using the method's actual parameters, you should check out PostSharp. It will allow you to inject code in a method body and then do some work based on the reflected method information you get from the .NET framework (and the actual parameters passed to the method at runtime).
我不确定我是否完全理解你的问题,但如果你试图在任意(随机)方法中调用Log.Entering和Log.Returning并使用方法的实际参数,你应该检查PostSharp。它允许您在方法体中注入代码,然后根据从.NET框架获得的反射方法信息(以及在运行时传递给方法的实际参数)执行一些工作。
#3
You could do it with Expression
easily enough - it would look something like:
您可以使用Expression轻松完成它 - 它看起来像:
Log.Capture(() => this.MethodOfDoom(arg1, arg2));
Here's an example; I've been a bit lazy using Compile().DynamicInvoke()
to read the arg-values - for real code I'd try to read it more directly:
这是一个例子;我一直懒得使用Compile()。DynamicInvoke()来读取arg值 - 对于真正的代码我会尝试更直接地读取它:
using System;
using System.Diagnostics;
using System.Linq.Expressions;
class Program
{
DateTime MethodOfDoom(string s, int i)
{
return DateTime.Today;
}
public void RunTest()
{
int i =123;
Log.Capture(() => this.MethodOfDoom("abc", i));
}
static void Main()
{
new Program().RunTest();
}
}
static class Log
{
public static T Capture<T>(Expression<Func<T>> method)
{
MethodCallExpression mce = method.Body as MethodCallExpression;
if (mce == null) throw new InvalidOperationException(
"Method-call expected");
string name = mce.Method.Name;
try
{
int i = 0;
foreach(var param in mce.Method.GetParameters())
{
object argValue = Expression.Lambda(mce.Arguments[i++])
.Compile().DynamicInvoke();
Trace.WriteLine(param.Name + "=" + argValue, name);
}
Trace.WriteLine("ENTERING", name);
T result = method.Compile().Invoke();
Trace.WriteLine("EXITING: " + result, name);
return result;
}
catch (Exception ex)
{
Trace.WriteLine("EXCEPTION: " + ex, name);
throw;
}
}
}
#4
If widely used in your code, this scenario is best implemented using Aspect Oriented Programming (AOP) techniques. There are different frameworks that can be used (such as Spring.NET AOP), which you can use in your .NET application. Here is a reference article that might help you get started:
如果在代码中广泛使用,则最好使用面向方面编程(AOP)技术实现此方案。可以使用不同的框架(例如Spring.NET AOP),您可以在.NET应用程序中使用它们。这是一篇可能有助于您入门的参考文章:
http://www.developer.com/lang/article.php/10924_3795031_2
The referenced article gives you the logging enter/exit scenario as an example.
引用的文章为您提供了日志记录输入/退出方案作为示例。
#5
I have used PostSharp to do this very thing before.
我之前使用PostSharp来做这件事。
#1
You can make your logging function take a MethodBase
argument and use MethodBase.GetCurrentMethod to pass the current method info as an argument.
您可以使您的日志记录函数采用MethodBase参数并使用MethodBase.GetCurrentMethod将当前方法信息作为参数传递。
Then, in the logger, you could check its properties Name
and DeclaringType
to get the method information. Also, passing parameters is easy by declaring a params object[] args
parameter in the logging function:
然后,在记录器中,您可以检查其属性Name和DeclaringType以获取方法信息。此外,通过在日志记录函数中声明params object [] args参数,可以轻松传递参数:
public static void Entering(object obj, MethodBase methodInfo,
params object[] args) {
Console.WriteLine("ENTERING {0}:{1}", methodInfo.DeclaringType.Name,
methodInfo.Name);
...
}
#2
I'm not sure I entirely understand your question, but if you are trying to make a call to Log.Entering and Log.Returning inside an arbitrary (random) method and using the method's actual parameters, you should check out PostSharp. It will allow you to inject code in a method body and then do some work based on the reflected method information you get from the .NET framework (and the actual parameters passed to the method at runtime).
我不确定我是否完全理解你的问题,但如果你试图在任意(随机)方法中调用Log.Entering和Log.Returning并使用方法的实际参数,你应该检查PostSharp。它允许您在方法体中注入代码,然后根据从.NET框架获得的反射方法信息(以及在运行时传递给方法的实际参数)执行一些工作。
#3
You could do it with Expression
easily enough - it would look something like:
您可以使用Expression轻松完成它 - 它看起来像:
Log.Capture(() => this.MethodOfDoom(arg1, arg2));
Here's an example; I've been a bit lazy using Compile().DynamicInvoke()
to read the arg-values - for real code I'd try to read it more directly:
这是一个例子;我一直懒得使用Compile()。DynamicInvoke()来读取arg值 - 对于真正的代码我会尝试更直接地读取它:
using System;
using System.Diagnostics;
using System.Linq.Expressions;
class Program
{
DateTime MethodOfDoom(string s, int i)
{
return DateTime.Today;
}
public void RunTest()
{
int i =123;
Log.Capture(() => this.MethodOfDoom("abc", i));
}
static void Main()
{
new Program().RunTest();
}
}
static class Log
{
public static T Capture<T>(Expression<Func<T>> method)
{
MethodCallExpression mce = method.Body as MethodCallExpression;
if (mce == null) throw new InvalidOperationException(
"Method-call expected");
string name = mce.Method.Name;
try
{
int i = 0;
foreach(var param in mce.Method.GetParameters())
{
object argValue = Expression.Lambda(mce.Arguments[i++])
.Compile().DynamicInvoke();
Trace.WriteLine(param.Name + "=" + argValue, name);
}
Trace.WriteLine("ENTERING", name);
T result = method.Compile().Invoke();
Trace.WriteLine("EXITING: " + result, name);
return result;
}
catch (Exception ex)
{
Trace.WriteLine("EXCEPTION: " + ex, name);
throw;
}
}
}
#4
If widely used in your code, this scenario is best implemented using Aspect Oriented Programming (AOP) techniques. There are different frameworks that can be used (such as Spring.NET AOP), which you can use in your .NET application. Here is a reference article that might help you get started:
如果在代码中广泛使用,则最好使用面向方面编程(AOP)技术实现此方案。可以使用不同的框架(例如Spring.NET AOP),您可以在.NET应用程序中使用它们。这是一篇可能有助于您入门的参考文章:
http://www.developer.com/lang/article.php/10924_3795031_2
The referenced article gives you the logging enter/exit scenario as an example.
引用的文章为您提供了日志记录输入/退出方案作为示例。
#5
I have used PostSharp to do this very thing before.
我之前使用PostSharp来做这件事。