c# – 使用Try-Catch块包装复杂的linq查询并捕获正确的异常

下面的代码是一个工厂类,它传递IGraph类型的对象,它实现了GraphTypeAttribute.在GraphFactory的静态构造函数中,通过使用
Linq来收集由Factory提供的适当类来构建列表.通常没有Linq我有一个循环和if-then的,可以用适当的try-catch块轻松包装.由于现在所有内容都填充在一个查询中,因此我对如何在此处实现正确的异常处理感到困惑.

所以我的问题是/是

>处理linq查询异常的最佳模式是什么.
>我应该在不同的查询中拆分它还是根本不使用linq?
>或者我在查询中有些东西可以消除不存在的元素,扫描错误的类等,查询重复值等(优化查询;).

查询的结果必须是工厂可以提供的所有类的列表.例如.用属性和接口实现装饰.

“工厂”,用于创建数据图形表示的对象:

    public sealed class GraphFactory 
    {
    static readonly GraphFactory _instance = new GraphFactory();
    static readonly IDictionary<string, Type> _items;
    static readonly Assembly _assembly = Assembly.GetExecutingAssembly();

    public static GraphFactory Instance { get { return _instance; } }
    GraphFactory() { }

    static GraphFactory() {
        try
        {
            _items = (from type in _assembly.GetTypes()
                      // filter from thatonly the classes with IGraph implemented
                      where type.GetInterface(typeof(IGraph).FullName) != null
                      // filter from thatonly the classes with GraphTypeAttribute imp.
                      from attribute in type.GetCustomAttributes(true)
                      where attribute is GraphTypeAttribute
                      select new { attribute, type })
                     // convert the result from anonymous to a dictionary
                      .ToDictionary(k => (k.attribute as GraphTypeAttribute).CustomType, 
                                          e => e.type);
        }
        /** EXH: non pokemon exception handling  * ........... * **/
    }

    public static IEnumerable<string> FriendlyNames  { get { return _items.Keys; } }

    public static IGraph CreateGraph(string friendlyName)
    {
        /** inspect argument, check it's a key 
            in the dictionary and throw exeptions if needed **/     

        IGraph result = null;
        try
        {
            result = _assembly.CreateInstance(_items[friendlyName].FullName) as IGraph;
        }
        /** non pokemon exception handling * ...........  * **/
        return result;
    }
}

界面(成员省略):

public interface IGraph { } 

用于装饰工厂分配的相应类的属性

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false,Inherited=true)]
public class GraphTypeAttribute : System.Attribute 
{ public GraphTypeAttribute(string friendlyName)  { } }

用属性装饰的类

[GraphTypeAttribute("piechart")]
public class PieChart : IGraph{ }

[GraphTypeAttribute("map")]
public class WorldMap : IGraph { }

[GraphTypeAttribute("horizontalbar")]
public class Bar : IGraph { }

[GraphTypeAttribute("verticalbar")]
public class VerticalBar : Bar { }

样品用量:

  foreach (string friendlyName in GraphFactory.FriendlyNames)
  {
   IGraph auth = GraphFactory.CreateGraph(friendlyName);
  }

非常感谢您对课程的任何其他意见或建议.

最佳答案 我认为这是
dynamic factory pattern的一个很好的例子.我一直这样做.我理解您对异常处理的担忧,但我认为没有必要这样做,仅仅是因为您的单元测试会阻止该工厂在生产过程中抛出,并且良好的单元测试可以将问题清楚地解释为异常消息.

但是如果你真的想要进行错误检查,你的LINQ查询将永远不会抛出异常.当有双键时,它会抛出ToDictionary.你可以做的是验证LINQ查询的结果并传递双键:

static GraphFactory()
{ 
    var items = (
        from type in _assembly.GetTypes()
        where type.GetInterface(typeof(IGraph).FullName) != null
        from attribute in type.GetCustomAttributes(true)
            .OfType<GraphTypeAttribute>
        select new { attribute, type }).ToArray();

    ValidateTypes(items);

    _item = items.ToDictionary(
        k => k.attribute.CustomType, e => e.type);
}

private static void ValidateTypes<T>(T[] items)
{
    var firstDoubleCustomType = (
        from item in items
        group item by item.attribute.CustomType into g
        where g.Count() > 1
        select g.Key).FirstOrDefault();

    if (firstDoubleCustomType != null)
    {
        throw new InvalidProgramException(
           "Doube: " + firstDoubleCustomType.ToString());
    }
}
点赞