我正在尝试将C# 5.0调用者信息与C# params关键字结合起来。我们的目的是为日志框架创建一个包装器,我们希望记录器能够像String.Format那样格式化文本。在以前的版本中,该方法如下所示:
void Log(
string message,
params object[] messageArgs = null);
我们这样称呼它:
log.Log("{0}: I canna do it cap'n, the engines can't handle warp {1}!",
"Scotty", warpFactor);
现在,我们希望捕获调用者的信息并将其记录下来。所以签名变成:
void Log(
string message,
params object[] messageArgs,
[CallerMemberName] string sourceMemberName = null);
这不能编译,因为params必须是最后一个参数。所以我试试看:
void Log(
string message,
[CallerMemberName] string sourceMemberName = null,
params object[] messageArgs);
有没有一种方法可以在不提供sourceMembername或显式地将messageArgs参数赋值为命名参数的情况下调用它?这样做违背了params关键字的目的:
// params is defeated:
log.Log("message",
messageArgs: new object[] { "Scotty", warpFactor });
// CallerMemberName is defeated:
log.Log("message", null,
"Scotty", warpFactor);
有办法这样做吗?似乎调用者信息被传递的"hacky“方式排除了使用params关键字。如果C#编译器认识到调用者成员信息参数根本不是真正的参数,那就太棒了。我看不出有必要显式地传递它们。
我的备份是跳过params关键字,调用方必须在最后一个示例中使用长签名。
发布于 2014-11-03 17:00:47
我认为这不可能完全按照你想要的方式去做。然而,我可以想到一些可行的解决办法,它们可能会给您带来几乎相同的好处。
log.Log("something")
,期望您的消息将被记录,不会发生任何事情。如果您使用Resharper,您可以通过向[Pure]
方法添加一个Log()
属性来减轻这一点,这样,如果有人没有对结果对象做任何事情,就会得到警告。你也可以稍微调整一下这个方法,说:
var log = logFactory.GetLog();// <--注入方法名。日志(“{0}:我要这样做,引擎不能处理翘曲{1}!","Scotty",warpFactor);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);
发布于 2014-11-03 17:37:43
要使用StriplingWarrior建议而不是委托,可以使用流畅的语法。
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)
{
}
}
那就叫它吧
Logger.Log().Message("{0}: I canna do it cap'n, the engines can't handle warp {1}!", "Scotty", 10);
记录器不一定是静态的,但它是演示这个概念的简单方法
发布于 2014-11-03 17:13:04
让我举一个选项;您可以使用反射来获得与CallMemberName
完全相同的名称。这肯定会慢一些。我相信,假设你不是每毫秒记录一次,那就足够承受压力了。
var stackTrace = new StackTrace(); var methodName = stackTrace.GetFrame(1).GetMethod().Name;
https://stackoverflow.com/questions/26718952
复制相似问题