构建一个自定义IDataReader,它在XML中查找与特定元素名称匹配的值,如果找到,则返回值。 GetValue函数 - 必须返回由接口指定的Object,如下所示:
public object GetValue(int i)
{
string SearchString = _columns[i];
var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
if (searchedAttributeValue.Count() > 0)
{
return ParseTypes(searchedAttributeValue.First().Value);
}
var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
if (searchedElementValue.Count() > 0)
{
return ParseTypes(searchedElementValue.First().Value);
}
}
显然,这不会构建,因为它可能在没有有效返回的情况下到达函数的末尾。
在这种情况下,如果发生这种情况,则意味着存在配置错误 - 用户正在寻找XML中不存在的元素或属性。
我发现(这对我来说是新的)你可以通过这样做解决问题:
public object GetValue(int i)
{
if (_el == null)
{
_el = XNode.ReadFrom(_reader) as XElement;
}
string SearchString = _columns[i];
var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
if (searchedAttributeValue.Count() > 0)
{
return ParseTypes(searchedAttributeValue.First().Value);
}
var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
if (searchedElementValue.Count() > 0)
{
return ParseTypes(searchedElementValue.First().Value);
}
throw new Exception("oh crap!");
}
因此该函数不会返回,只会抛出错误。
但是,这种方法存在根本性的错误。它没关系,为什么它没关系/不好,是否有更好的方法来处理这种情况?
答案 0 :(得分:6)
除非你真的需要 catch
块,否则你不需要引入try / catch / finally。您可以在初始方法的末尾添加throw
语句。
一路上,我开始使用FirstOrDefault()
,遵循局部变量的正常C#命名约定,当它们不是非常有用时停止使用查询表达式,并抛出一个更具体的异常:
public object GetValue(int i)
{
string searchString = _columns[i];
var searchedAttribute = _el.Attributes(searchString).FirstOrDefault();
if (searchedAttribute != null)
{
return ParseTypes(searchedAttribute.Value);
}
var searchedElement = _el.Elements(searchString).FirstOrDefault();
if (searchedElement != null)
{
return ParseTypes(searchedElement.Value);
}
// Nothing found - oops.
throw new SomeSpecificException("Some message here");
}
如果您需要catch块进行日志记录,我可能会尝试捕获特定的异常,这可能意味着无论如何都要将其移入ParseTypes
(因为您不应该&#39} ; t从其余调用中获取任何异常...)无论哪种方式,最后都要保留throw
语句。
编辑:在设计方面,是否应该在未找到值时抛出异常,实际上取决于期望值。我们无法知道这是否表明系统出现了问题,或者只是完全正常的数据缺失。这应该决定你的选择。特别是,如果每个调用者都试图捕获异常,那么这就是设计气味,您应该返回null
或使用类似Dictionary<,>.TryGetValue
方法的东西。
答案 1 :(得分:2)
我喜欢使我的方法类似于.NET框架Parse()和TryParse()方法。在你的情况下,我会做:
public object GetValue(int i)
{
// ...
// fail
throw new Exception("Cannot get value");
}
或做:
public bool TryGetValue(int i, out object result)
{
// ...
// fail
result = null;
return false;
}
答案 2 :(得分:1)
尝试捕获是无关紧要的。你可以简单地将你的代码重构为:
public object GetValue(int i)
{
if (_el == null)
{
_el = XNode.ReadFrom(_reader) as XElement;
}
string SearchString = _columns[i];
var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
if (searchedAttributeValue.Count() > 0)
{
return ParseTypes(searchedAttributeValue.First().Value);
}
var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
if (searchedElementValue.Count() > 0)
{
return ParseTypes(searchedElementValue.First().Value);
}
throw new Exception("oh crap!");
}
这具有相同的净结果。
那说抛出异常是昂贵的(计算)。如果你想要炸弹(完全停止处理,这是一个主要问题,它应该只是死)然后抛出一个异常。
如果只是一种确定何时未满足if
语句的方法,可以将其更改为TryParse
类型函数:
public bool GetValue(int i, out object returnVal)
{
if (_el == null)
{
_el = XNode.ReadFrom(_reader) as XElement;
}
string SearchString = _columns[i];
var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
if (searchedAttributeValue.Count() > 0)
{
returnVal = ParseTypes(searchedAttributeValue.First().Value);
return true;
}
var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
if (searchedElementValue.Count() > 0)
{
returnVal = ParseTypes(searchedElementValue.First().Value);
return true;
}
return false;
}
然后
if (GetValue(i, out value))
//success
else
//it's failed.
答案 3 :(得分:1)
如果由于配置错误而导致搜索不会返回任何内容的真正特殊情况,那么无论如何都要抛出异常。这个问题是延续的。如果找不到项目,客户端代码是否可以继续?如果可以的话,客户端代码将需要仔细检查从您的代码抛出的任何异常,以确定它是否因为某个项目不存在而被抛出,或者因为其他错误而无法继续执行。
另一个选项是返回指示未找到值的内容,并允许调用代码来处理它。您可以返回null
以指示调用代码没有找到任何项目,并且在此实例中可能没问题。一个更好的解决方案可能是创建一个简单的Optional<T>
类,它包含对象是否存在(可能是HasValue
)的指示,以及对象本身(如果有)。调用代码可以轻松,更具体地检查对象是否被返回并处理不存在的情况,并且异常不需要额外的审查。
编辑:一个更好的替代方案可能是其他人提出的Parse
和TryParse
范例,但我认为这个答案可能有一些用处,所以我会留在这里:)
答案 4 :(得分:0)
这种方法有很多不好的做法:应始终避免使用catch (Exception)
。只捕捉你期望的例外。另外,throw Exception()
是不好的风格。总是扔一些更具体的东西。但是对于你正在寻找的东西:毕竟你根本不需要一个,只需要放置一个throw new ArgumentException()
或者其他东西作为函数的最后一行。这是一个很好的做法,如果代码曾在那里运行,那真的是一个编程错误。