问题 为什么C#调用者信息属性需要默认值?


我刚刚遇到了C#5来电者信息属性(http://msdn.microsoft.com/en-us/library/hh534540.aspx)。

这似乎是一个非常有用的功能,我已经阅读了一些文档(http://www.codeproject.com/Tips/606379/Caller-Info-Attributes-in-Csharp)。

但是,我只是想知道:为什么必须传递默认值?它们是如何使用的?

以下示例代码显示了如何使用调用者信息属性:

public static void ShowCallerInfo([CallerMemberName] 
  string callerName = null, [CallerFilePath] string 
  callerFilePath = null, [CallerLineNumber] int callerLine=-1)
{
    Console.WriteLine("Caller Name: {0}", callerName);
    Console.WriteLine("Caller FilePath: {0}", callerFilePath);
    Console.WriteLine("Caller Line number: {0}", callerLine);
}

我的问题是:什么是默认值 nullnull,和 -1 用于?上面的代码与以下内容有何不同:

public static void ShowCallerInfo([CallerMemberName] 
  string callerName = "hello", [CallerFilePath] string 
  callerFilePath = "world", [CallerLineNumber] int callerLine=-42)
{
    Console.WriteLine("Caller Name: {0}", callerName);
    Console.WriteLine("Caller FilePath: {0}", callerFilePath);
    Console.WriteLine("Caller Line number: {0}", callerLine);
}

我理解它的方式,这些是可选参数,编译器提供默认值,替换我们分配的任何默认值。在那种情况下,我们为什么要指定默认值?是否有一些奇怪的边缘情况,编译器可能无法填写值,并转向我们提供的默认值?如果没有,那么为什么要求我们输入这些数据呢?要求开发者提供永远不会使用的默认值似乎相当笨拙。

免责声明:我试过谷歌搜索,但我找不到任何东西。我几乎害怕在SO上提问,因为大多数这样的新手问题都遭遇了这种敌意,但作为最后的手段,我会冒一个问题。主持人/高级用户,没有违法行为 - 在发布此内容之前,我确实尝试过在其他地方查找信息。


3699
2018-06-23 03:25


起源

请不要误会 “你尝试了什么?” 回答充满敌意。鼓励简洁,不管它看起来多冷。一个问题的新奇可以通过你获得的谷歌点击次数来判断。如果你不能在google上找到相当多的查询,那可能不是一个微不足道的问题。这个问题不是微不足道的,我喜欢阅读答案。 - Gusdor


答案:


这些参数需要默认值,因为Caller Info属性是使用可选参数实现的,可选参数需要默认值。通过这种方式,通话可以很简单 ShowCallerInfo() 无需发送任何参数,编译器将添加相关参数。

为什么使用可选参数实现它是一个更深层次的问题。他们 可以 已经没有了,编译器需要“注入”那些参数 之前 实际编译开始,但与可选参数(这是一个 C# 4.0 它会 不向后兼容,它将破坏其他编译器/代码分析工具


7
2018-06-23 10:40



我是否正确理解开发C#(master devs?)的“开发人员”是否因为向后兼容性等问题而以一种hacky方式实现此功能?旧版本的c#编译器不支持新属性(因此仍然会出错吗?)这对后向兼容性有何帮助? - Omaer
@Omaer如果您使用支持可选参数的旧编译器,代码可以编译,因为它有一个默认值。您只需不断打印默认值。我不会称之为黑客,更多地依赖现有功能。 - i3arnon
所以你的意思是说较旧的编译器会忽略它 [CallerMemberName] (和其他两个)属性,即使他们不知道那些属性是做什么的? - Omaer
@Omaer是的,为什么不呢?您可以创建所需的任何属性并将其应用于参数/方法/等。编译器没有理由会介意。 然而 这些类是.net 4.5的一部分,因此当使用旧框架时,您需要将它们实现为存根。 - i3arnon
好吧,那么这是有道理的 - 人们仍然必须将属性实现为存根。我不确定这是否是我们的Master Devs实现此功能的最佳方式,但我认为声明一些属性存根肯定更容易,而不是从代码中删除所有属性。 - Omaer


它们需要默认值,以便可以将参数标记为可选。如果在调用方法时未指定参数,编译器将为您注入正确的值,但前提是您未指定它们。如果你这样做,那么这些属性的“神奇”就不会发生。

根据我的理解,这些属性不会影响运行时,纯粹是为了编译时间,因此默认值只是为了确保参数是可选的。


4
2018-06-23 03:30





换句话说,在被调用者(调用属性应用于参数的方法)上,参数必须存在。另一方面,调用者必须传递这些参数,并且编译器允许未指定参数的唯一方法是为其提供默认值。

虽然属性可能会影响代码生成或运行时执行,但如果删除了所有属性,则源必须有效。因此,必须在被调用者上定义默认值,并且编译器只根据应用的属性生成参数值,而不是在被调用者上定义的当前默认值。


2
2018-06-23 15:09