我应该如何重构一连串的尝试和捕获包裹的投机性投机操作

Phi*_*oth 3 .net c# refactoring xsd try-catch

我有一些C#代码使用.NET框架中的Xml.Schema类来处理XML模式.各种简单类型限制在框架中被抽象为从Xml.Schema.XmlSchemaFacet派生的一大堆类.除非有一些我错过的东西,否则知道给定方面的哪个派生方面类型的唯一方法是推测性地将其转换为其中一个,在失败的情况下捕获结果的InvalidCastOperation.这样做会让我有一个非常难看的功能:

private void NavigateFacet(XmlSchemaFacet facet)
{
    try
    {
        handler.Length((XmlSchemaLengthFacet)facet);
    }
    catch(InvalidCastException)
    {
        try
        {
            handler.MinLength((XmlSchemaMinLengthFacet)facet);
        }
        catch(InvalidCastException)
        {
            try
            {
                handler.MaxLength((XmlSchemaMaxLengthFacet)facet);
            }
            catch(InvalidCastException)
            {
                ...
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为必须有更优雅的方法来做到这一点; 要么使用我从.NET框架中遗漏的一些属性,要么使用一些聪明的OO技巧.任何人都可以开导我吗?

Rob*_*ney 7

因为我更喜欢将数据调试到调试代码,所以我会这样做,特别是如果代码必须处理所有XmlSchemaFacet子类:

Dictionary<Type, Action<XmlSchemaFacet>> HandlerMap = 
   new Dictionary<Type, Action<XmlSchemaFacet>>
{
   {typeof(XmlSchemaLengthFacet), handler.Length},
   {typeof(XmlSchemaMinLengthFacet), handler.MinLength},
   {typeof(XmlSchemaMaxLengthFacet), handler.MaxLength}
};

HandlerMap[facet.GetType()](facet);
Run Code Online (Sandbox Code Playgroud)

这将抛出一个KeyNotFoundExceptionif facet不是已知类型.请注意,所有处理程序方法都必须从中转换参数XmlSchemaFacet,因此您可能不会保存代码总数,但您肯定会节省代码中的路径数.

还有一点(假设地图是预先构建的)将字典映射到具有字典的方法将比遍历线性类型列表更快,这实质上是使用一堆if块获取的.


Mat*_*nit 6

您可以尝试使用该as关键字.其他一些人建议使用is关键字.我发现是为什么as更好的一个很好的解释.

一些示例代码:

private void NavigateFacet(XmlSchemaFacet facet)
{
  XmlSchemaLengthFacet lengthFacet = facet as XmlSchemaLengthFacet;
  if (lengthFacet != null)
  {
    handler.Length(lengthFacet);
  }
  else
  {
    // Re-try with XmlSchemaMinLengthFacet, etc.
  }
}
Run Code Online (Sandbox Code Playgroud)