首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在C#中使用params关键字和调用者信息?

如何在C#中使用params关键字和调用者信息?
EN

Stack Overflow用户
提问于 2014-11-03 16:51:43
回答 4查看 2.6K关注 0票数 9

我正在尝试将C# 5.0调用者信息与C# params关键字结合起来。我们的目的是为日志框架创建一个包装器,我们希望记录器能够像String.Format那样格式化文本。在以前的版本中,该方法如下所示:

代码语言:javascript
运行
复制
void Log(
   string message,
   params object[] messageArgs = null);

我们这样称呼它:

代码语言:javascript
运行
复制
log.Log("{0}: I canna do it cap'n, the engines can't handle warp {1}!", 
        "Scotty", warpFactor);

现在,我们希望捕获调用者的信息并将其记录下来。所以签名变成:

代码语言:javascript
运行
复制
void Log(
    string message,
    params object[] messageArgs,
    [CallerMemberName] string sourceMemberName = null);

这不能编译,因为params必须是最后一个参数。所以我试试看:

代码语言:javascript
运行
复制
void Log(
    string message,
    [CallerMemberName] string sourceMemberName = null,
    params object[] messageArgs);

有没有一种方法可以在不提供sourceMembername或显式地将messageArgs参数赋值为命名参数的情况下调用它?这样做违背了params关键字的目的:

代码语言:javascript
运行
复制
// params is defeated:
log.Log("message", 
        messageArgs: new object[] { "Scotty", warpFactor });
// CallerMemberName is defeated:
log.Log("message", null,
        "Scotty", warpFactor);

有办法这样做吗?似乎调用者信息被传递的"hacky“方式排除了使用params关键字。如果C#编译器认识到调用者成员信息参数根本不是真正的参数,那就太棒了。我看不出有必要显式地传递它们。

我的备份是跳过params关键字,调用方必须在最后一个示例中使用长签名。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-11-03 17:00:47

我认为这不可能完全按照你想要的方式去做。然而,我可以想到一些可行的解决办法,它们可能会给您带来几乎相同的好处。

  1. 使用中间方法调用来捕获调用方成员名。第一个方法调用返回一个委托,然后调用该委托来提供附加参数。这看起来很奇怪,但它应该能用: log.Log()("{0}:我要这样做,引擎不能处理翘曲{1}!","Scotty",warpFactor); 这里的一个缺点是可以调用log.Log("something"),期望您的消息将被记录,不会发生任何事情。如果您使用Resharper,您可以通过向[Pure]方法添加一个Log()属性来减轻这一点,这样,如果有人没有对结果对象做任何事情,就会得到警告。你也可以稍微调整一下这个方法,说: var log = logFactory.GetLog();// <--注入方法名。日志(“{0}:我要这样做,引擎不能处理翘曲{1}!","Scotty",warpFactor);
  2. 使用lambdas生成日志消息,并让string.Format处理params数组: log.Log(() => string.Format("{0}:我要这样做,引擎不能处理翘曲{1}!","Scotty",warpFactor)); 这是我通常使用的方法,它有一些副作用:

代码语言:javascript
运行
复制
1. Your log method can catch exceptions produced while producing the debug string, so instead of breaking your system you just get an error that says: "Failed to produce log message: [exception details]".
2. Sometimes the object you pass to your format string might incur additional cost, which you'd only want to incur when you need it:

log.Info(() => string.Format("{0}:我要做,引擎不能处理翘曲{1}!",_db.GetCurrentUsername(),warpFactor));

如果没有打开信息级别的日志记录,您希望不让上面的代码执行数据库访问。

顺便提一句,我发现自己经常使用string.Format,以至于我创建了一个帮助器方法来稍微缩短语法:

log.Log(() ) => "{0}:我要做它,引擎不能处理翘曲{1}!“.With("Scotty",warpFactor);

票数 8
EN

Stack Overflow用户

发布于 2014-11-03 17:37:43

要使用StriplingWarrior建议而不是委托,可以使用流畅的语法。

代码语言:javascript
运行
复制
public static class Logger
{
    public static LogFluent Log([CallerMemberName] string sourceMemberName = null)
    {
        return new LogFluent(sourceMemberName);
    }
}

public class LogFluent
{
    private string _callerMemeberName;

    public LogFluent(string callerMamberName)
    {
        _callerMemeberName = callerMamberName;
    }

    public void Message(string message, params object[] messageArgs)
    {

    }
}

那就叫它吧

代码语言:javascript
运行
复制
Logger.Log().Message("{0}: I canna do it cap'n, the engines can't handle warp {1}!", "Scotty", 10);

记录器不一定是静态的,但它是演示这个概念的简单方法

票数 5
EN

Stack Overflow用户

发布于 2014-11-03 17:13:04

让我举一个选项;您可以使用反射来获得与CallMemberName完全相同的名称。这肯定会慢一些。我相信,假设你不是每毫秒记录一次,那就足够承受压力了。

var stackTrace = new StackTrace(); var methodName = stackTrace.GetFrame(1).GetMethod().Name;

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26718952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档