C# 将任何方法作为参数传递

发布于 2024-10-27 06:13:42 字数 1588 浏览 1 评论 0 原文

记录日志时,您总是会与字符串文字纠缠在一起。

我通过传递 Expression> 很好地解决了属性、字段和变量的问题。表达式 (如解释这里),所以你可以做这样的事情:

public void Demo(string someArgument)
{
    LogFrameWork.LogLine("Demo"); // goal is to get rid of these string literals
    LogFramework.Log(() => someArgument);
}

我想对方法 Demo 本身做类似的事情:

public void Demo(string someArgument)
{
    LogFramework.Log(this.Demo);
}

我尝试了这样的事情:

public static void Log(Delegate method)
{
    string methodName = method.Method.Name;
    LogLine(methodName);
}

和这样的:

public static void Log(Action method)
{
    string methodName = method.Method.Name;
    LogLine(methodName);
}

但是我得到了这样的编译器错误:

Argument 1: cannot convert from 'method group' to 'System.Delegate' 
Argument 1: cannot convert from 'method group' to 'System.Action'   

我可以使用 Func<...>Action<...>,但这听起来过于复杂。

对于具有任意数量的参数和可选结果的任何方法,有没有办法解决这个问题?

--jeroen

PS:我认为这个问题可能在这里有一些相关性,但没有答案这让我有一种“啊哈”的感觉:-)

When logging, you always get entangled in string literals.

I solved that nicely for properties, fields and variables by passing an Expression<Func<T>> expression (as explained here), so you can do things like this:

public void Demo(string someArgument)
{
    LogFrameWork.LogLine("Demo"); // goal is to get rid of these string literals
    LogFramework.Log(() => someArgument);
}

I want to do something similar for the method Demo itself:

public void Demo(string someArgument)
{
    LogFramework.Log(this.Demo);
}

I tried things like this:

public static void Log(Delegate method)
{
    string methodName = method.Method.Name;
    LogLine(methodName);
}

and this:

public static void Log(Action method)
{
    string methodName = method.Method.Name;
    LogLine(methodName);
}

But I get compiler errors like these:

Argument 1: cannot convert from 'method group' to 'System.Delegate' 
Argument 1: cannot convert from 'method group' to 'System.Action'   

I could introduce a bunch of overloads using Func<...> and Action<...>, but that sounds overly complex.

Is there a way to cover this for any method with any number of parameters and an optional result?

--jeroen

PS: I think this question might have some relevance here, but no answers that got me a 'aha' feeling :-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

影子的影子 2024-11-03 06:13:42

您也可以通过 System.Diagnostics.StackTrace 实现此目的,无需使用 ExpressionTree。

StackTrace trace = new StackTrace();

然后:

trace.GetFrame(0).GetMethod().Name

获取 MethodInfo 以及当前方法的名称,或者:

trace.GetFrame(1).GetMethod().Name 

获取调用方法。

You can also achieve this without using ExpressionTrees through System.Diagnostics.StackTrace.

StackTrace trace = new StackTrace();

And then:

trace.GetFrame(0).GetMethod().Name

To get the MethodInfo and then name of the current method, or:

trace.GetFrame(1).GetMethod().Name 

To get the calling method.

独夜无伴 2024-11-03 06:13:42

这比看起来要难得多。我认为您可能最适合使用通用 Func 和 Action 重载,但是有一种方法可以使用表达式树来做到这一点。下面是 LINQPad 中的一个示例:

public static void Log(Expression<Action> expr)
{
    Console.WriteLine(((MethodCallExpression)expr.Body).Method.Name);
}

void Main()
{
    Log(() => DoIt());
    Log(() => DoIt2(null));
    Log(() => DoIt3());
}

public void DoIt()
{
    Console.WriteLine ("Do It!");
}

public void DoIt2(string s)
{
    Console.WriteLine ("Do It 2!" + s);
}

public int DoIt3()
{
    Console.WriteLine ("Do It 3!");
    return 3;
}

此输出:

DoIt
DoIt2
DoIt3

请注意,在调用 Log 方法时,我必须使用 lambda 并指定虚拟参数。

这是基于 Fyodor Soikin 的出色答案

This is much harder than it looks. I think you might be best with the generic Func and Action overloads, but there is a way to do this with expression trees. Here's an example in LINQPad:

public static void Log(Expression<Action> expr)
{
    Console.WriteLine(((MethodCallExpression)expr.Body).Method.Name);
}

void Main()
{
    Log(() => DoIt());
    Log(() => DoIt2(null));
    Log(() => DoIt3());
}

public void DoIt()
{
    Console.WriteLine ("Do It!");
}

public void DoIt2(string s)
{
    Console.WriteLine ("Do It 2!" + s);
}

public int DoIt3()
{
    Console.WriteLine ("Do It 3!");
    return 3;
}

This outputs:

DoIt
DoIt2
DoIt3

Note that I had to use lambdas and specify dummy arguments when calling the Log method.

This is based on Fyodor Soikin's excellent answer.

甜点 2024-11-03 06:13:42

不要尝试将方法作为参数传递给记录器,而是从让记录器识别调用方法的角度来看待它。

这是一个(伪)示例:

Logger Class

public void Debug( string message )
{
  message = string.Format( "{0}: {1}", GetCallingMethodInfo(), message );
  // logging stuff
}

/// <summary>
/// Gets the application name and method that called the logger.
/// </summary>
/// <returns></returns>
private static string GetCallingMethodInfo()
{
  // we should be looking at the stack 2 frames in the past:
  // 1. for the calling method in this class
  // 2. for the calling method that called the method in this class
  MethodBase method = new StackFrame( 2 ).GetMethod();
  string name = method.Name;
  string type = method.DeclaringType.Name;

  return string.Format( "{0}.{1}", type, name );
}

在任何使用记录器的地方:

// resides in class Foo
public void SomeMethod()
{
  logger.Debug("Start");
}

记录器的输出将是:Foo.SomeMethod: Start

Instead of trying to pass the method in as a parameter to your logger, look at it from the perspective of having the logger identify the calling method.

Here's an (pseudo) example:

Logger Class

public void Debug( string message )
{
  message = string.Format( "{0}: {1}", GetCallingMethodInfo(), message );
  // logging stuff
}

/// <summary>
/// Gets the application name and method that called the logger.
/// </summary>
/// <returns></returns>
private static string GetCallingMethodInfo()
{
  // we should be looking at the stack 2 frames in the past:
  // 1. for the calling method in this class
  // 2. for the calling method that called the method in this class
  MethodBase method = new StackFrame( 2 ).GetMethod();
  string name = method.Name;
  string type = method.DeclaringType.Name;

  return string.Format( "{0}.{1}", type, name );
}

Anywhere that uses the logger:

// resides in class Foo
public void SomeMethod()
{
  logger.Debug("Start");
}

The output from the logger will then be: Foo.SomeMethod: Start

我很坚强 2024-11-03 06:13:42

您可以定义一个委托,然后接受该委托作为参数。

public delegate void DemoDelegate(string arg);

public void MyMethod(DemoDelegate delegate)
{
    // Call the delegate
    delegate("some string");
}

您可以像这样调用 MyMethod:

MyMethod(delegate(string arg) 
{
   // do something
});

void MethodThatTakesAString(string value)
{
    // do something
}

MyMethod(MethodThatTakesAString);

查看此链接以获取更多信息:

http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx

You can define a delegate, then accept that delegate as a parameter.

public delegate void DemoDelegate(string arg);

public void MyMethod(DemoDelegate delegate)
{
    // Call the delegate
    delegate("some string");
}

You can call MyMethod like this:

MyMethod(delegate(string arg) 
{
   // do something
});

or

void MethodThatTakesAString(string value)
{
    // do something
}

MyMethod(MethodThatTakesAString);

See this link for more information:

http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx

眼泪淡了忧伤 2024-11-03 06:13:42

试试这个:

/// <summary>
/// Trace data event handler delegate.
/// </summary>
/// <returns>The data to write to the trace listeners</returns>
public delegate object TraceDataEventHandler();

public static class Tracing
{

    /// Trace a verbose message using an undefined event identifier and message.
    /// </summary>
    /// <param name="message">The delegate to call for the trace message if this event should be traced.</param>
    [Conditional("TRACE")]
    public static void TraceVerbose(TraceMessageEventHandler message)
    {
        ... your logic here
    }
}

然后你可以做...

Tracing.TraceVerbose(() => String.Format(...));

我希望我正确理解了你的问题...这符合你的要求吗?

Try this:

/// <summary>
/// Trace data event handler delegate.
/// </summary>
/// <returns>The data to write to the trace listeners</returns>
public delegate object TraceDataEventHandler();

public static class Tracing
{

    /// Trace a verbose message using an undefined event identifier and message.
    /// </summary>
    /// <param name="message">The delegate to call for the trace message if this event should be traced.</param>
    [Conditional("TRACE")]
    public static void TraceVerbose(TraceMessageEventHandler message)
    {
        ... your logic here
    }
}

Then you can do...

Tracing.TraceVerbose(() => String.Format(...));

I hope I have understood your question correctly... does this do what you want?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文