Combining a complex linq query with a try-catch block and choosing the right Exceptions

Below is the factory code that provides IGraph objects that have an implemented GraphTypeAttribute. Inside the GraphFactory static constructor, a list is created using Linq to collect the appropriate classes that will be delivered to Factory. Usually without Linq, I had a loop of loops, and if it could then be easily wrapped by the corresponding try-catch blocks. Since everything is filled with one request, I got a little confused about how to implement the correct data access here .

So my question is / are

  • What is the best pattern for handling exceptions in a linq query.
  • Should I split it into different requests or not use linq at all?
  • Or am I doing something in a query that can eliminate non-existent elements, scan for invalid classes, etc., request duplicate values, etc. (query optimization;).

The query result should be a list of all classes that the factory can provide. For instance. decorated with an attribute and implemented interface.

A "Factory" that creates objects for graphically presenting data:

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

interface (members omitted):

 public interface IGraph { } 

to decorate the appropriate classes for factory assigment

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

attribute decorated classes

 [GraphTypeAttribute("piechart")] public class PieChart : IGraph{ } [GraphTypeAttribute("map")] public class WorldMap : IGraph { } [GraphTypeAttribute("horizontalbar")] public class Bar : IGraph { } [GraphTypeAttribute("verticalbar")] public class VerticalBar : Bar { } 

Sample Usage:

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

Any other comments or class recommendations are greatly appreciated.

+4
source share
1 answer

I think this is a good example of a dynamic factory pattern . I do this all the time. I understand your concern about exception handling, but I think this is not necessary, simply because your unit tests will prevent this factory from ever throwing during production, and a good unit test can explain how the problem is like a message about the exception.

But if you really want to perform error checking, your LINQ query will never throw an exception. This is a ToDictionary that will throw when there is a double key. What you can do is check LINQ query results and pass double keys:

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

All Articles