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

时间:2011-03-26 16:09:31

标签: c# methods parameters

记录时,你总是纠缠在字符串文字中。

我通过传递Expression<Func<T>> expression(如here所解释的那样)很好地解决了属性,字段和变量,所以你可以这样做:

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:我认为this question可能在这里有一些相关性,但没有让我感到'aha'感觉的答案: - )

5 个答案:

答案 0 :(得分:5)

您也可以在不使用Expression System.Diagnostics.StackTrace的情况下实现此目的。

StackTrace trace = new StackTrace();

然后:

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

获取MethodInfo,然后获取当前方法的名称,或者:

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

获取调用方法。

答案 1 :(得分:5)

这比它看起来要困难得多。我认为你可能最好使用泛型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

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

这基于Fyodor Soikin's excellent answer

答案 2 :(得分:3)

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

这是一个(伪)示例:

记录器类

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

试试这个:

/// <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(...));

我希望我能正确理解你的问题......这样做你想要的吗?