()=>与仅直接获取属性的目的

时间:2018-06-20 14:09:15

标签: c#

因此,我正在学习更多C#,并遇到了以下语法:

Log.Info(() => $"Some Text {SomeVariableorProperty}");

这与以下内容有何不同?

Log.Info($"Some Text {SomeVariableorProperty}");

我知道()=>本质上是一个委托,但不确定其用途是什么。

2 个答案:

答案 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);

这里messagestring,但是您看到[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决定不需要对其进行记录(例如,根据设置来说太冗长了),则可以绕过昂贵的消息生成过程。就像我说的那样-很少会遇到这种情况,并且可能表明已记录过多。