因此,我正在学习更多C#,并遇到了以下语法:
Log.Info(() => $"Some Text {SomeVariableorProperty}");
这与以下内容有何不同?
Log.Info($"Some Text {SomeVariableorProperty}");
我知道()=>本质上是一个委托,但不确定其用途是什么。
答案 0 :(得分:19)
场景是:
Log.Info(() => $"Some Text {SomeSlowMethod()}");
public static string SomeSlowMethod()
{
Thread.Sleep(5000);
return "Foo";
}
现在...如果禁用Info
的日志记录会怎样?叫SomeSlowMethod
吗?答案是不!因为委托() => $"Some Text {SomeSlowMethod()}
的调用是由Log.Info()
(如果需要的话)完成的。与之比较:
Log.Info($"Some Text {SomeSlowMethod()}");
现在总是调用SomeSlowMethod()
,并且Log.Info
可能会忽略其值。
如果您认为在实际情况下不存在SomeSlowMethod()
,请记住,与其他操作相比,即使字符串组成也很“慢”。简单地做无用的string.Format
($"Some Text {SomeVariableorProperty}
是string.Format
)是浪费时间。好的日志库的法则之一是,如果它不处于活动状态,则不会降低应用程序的速度。
要进行有趣的比较,请Debug.Assert()
:
[Conditional("DEBUG")]
public static void Assert(bool condition, string message);
这里message
是string
,但是您看到[Conditional(...)]
吗?如果未在编译时定义DEBUG
,则C#编译器可以删除整个Debug.Assert()
方法调用,甚至删除Debug.Assert()
内部调用的所有方法,因此可以修改效果:
Debug.Assert(false, Throw());
public static string Throw()
{
throw new Exception();
}
如果未定义DEBUG
(因此您正在执行RELEASE
构建),它将转换为:
; // nothing
因此没有throw
(例如参见this)。但是请注意,必须在编译时解决此问题,而日志库是在 runtime 上配置的。
答案 1 :(得分:5)
这意味着exec ./docker-entrypoint.sh $@ -Djgroups.bind_addr=$EXTERNAL_ADDR
方法期望带有签名Log.Info
的函数,本质上是一个无参数的函数,它将返回一个字符串。
在构建时直接传递Func<String>
会失败,因为这是$"Some Text {SomeVariableorProperty}"
而不是可以执行的功能。也就是说-除非方法本身具有仅接受String
的重载。
如果您完全控制代码,则完全同意这有点奇怪,我看不出有强烈的理由希望在String
上使用函数。
如@KirkLarkin所建议的,唯一的好用例是是否需要以惰性方式完成该Log消息的生成。您可能只在极端情况下才需要这样做,在这种情况下,创建要记录的实际消息是一项昂贵的操作。这样,如果您致电String
决定不需要对其进行记录(例如,根据设置来说太冗长了),则可以绕过昂贵的消息生成过程。就像我说的那样-很少会遇到这种情况,并且可能表明已记录过多。