让我们从摆脱异常"处理"开始吧.未找到的节点是"合理预期"的错误,我们要确保不会导致异常.应该抛出其他异常 - 例如根本找不到文件,或者不是有效的XML.
接下来,让我们停止使用查询表达式 - 当你只使用一个select
子句时,它并没有真正为你买任何东西.
作为下一步,我将停止分配configFilePath
可能是一个字段.写这个字段作为副作用对我来说似乎是一个非常糟糕的主意.让我们Path.Combine
用来组合路径的各个部分......
所以现在我们有了:
// Work in progress! public static string ReadConfigurationFile( string configurationFileName, string root, string section, string name) { string currentDirectory = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location); var fullConfigPath = Path.Combine( Directory.GetParent(currentDirectory), configurationFolder, configurationFileName); var configXml = XDocument.Load(fullConfigPath); return configXml.Descendants(root) .Descendants(section) .Select(x => x.Element(name).Attribute("value").Value .First(); }
如果它找不到元素或属性,那么现在将抛出异常.我们可以像这样修复:
return configXml.Descendants(root) .Descendants(section) .Elements(name) .Select(x => (string) x.Attribute("value")) .FirstOrDefault();
现在,如果Elements()
返回一个空序列,则没有任何内容可供选择,FirstOrDefault()
并将返回null.如果是一个元素,它不具有的value
属性,x.Attribute("value")
将返回null,并从显式转换XAttribute
到string
将返回null.
虽然我们正在使用它,但我们只使用configXml
一个电话,所以让我们记住,留下我们:
public static string ReadConfigurationFile( string configurationFileName, string root, string section, string name) { string currentDirectory = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location); var fullConfigPath = Path.Combine( Directory.GetParent(currentDirectory), configurationFolder, configurationFileName); return XDocument.Load(fullConfigPath) .Descendants(root) .Descendants(section) .Elements(name) .Select(x => (string) x.Attribute("value")) .FirstOrDefault(); }
现在,返回null
而不是原始代码所做的空字符串.我认为这更好,因为:
它允许呼叫者从"未提供设置"中区分"设置已提供但为空"
它允许调用者使用null-coalescing运算符来指定默认值:
var setting = ReadConfigurationFile("a", "b", "c", "d") ?? "some default value";