代码之家  ›  专栏  ›  技术社区  ›  Caspar Kleijne

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

  •  4
  • Caspar Kleijne  · 技术社区  · 14 年前

    下面的代码是一个工厂类,它传递实现了GraphTypeAttribute的IGraph类型的对象。在GraphFactory的静态构造函数中,通过使用Linq收集工厂要交付的适当类来构建一个列表。通常没有Linq,我有一个buch循环,如果then的,可以很容易地用适当的try-catch块包装。 由于所有的查询都被塞进了一个查询中,所以我对如何在这里实现适当的异常处理有点困惑 .

    所以我的问题是

    • 我应该把它分成不同的查询还是根本不用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);
      }
    

    感谢您对本课程的任何其他评论或建议。

    1 回复  |  直到 14 年前
        1
  •  2
  •   Steven    14 年前

    我认为这是一个很好的例子 dynamic factory pattern

    但是如果您真的想进行错误检查,您的LINQ查询将永远不会抛出异常。它是 ToDictionary

    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());
        }
    }