The below code is a factory class that is delivers objects of type IGraph that have the GraphTypeAttribute implemented. Inside the static constructor of the GraphFactory, a list is built by using Linq to collect the appropriate classes to be delivered by the Factory. Normally without Linq I had a buch of loops and if-then's that could be wrapped easily with appropriate try-catch blocks. Since all is stuffed in one query now I am a bit confused on how to implement proper exceptionhandling here.
So my question(s) is/are
- What is the best pattern to handle exceptions on the linq query.
- Should I split it in different queries or not use linq at all?
- Or am I mising something in the query that can eliminate non-existing elements, scanning wrong classes etc, querying duplicate values etc (optimizing the query ;).
The result of the query must be a list of all classes that the factory can deliver. E.g. decorated with the attribute and the interface implemented.
A "Factory" that creates objects for graphical representation of 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'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;
}
}
the interface (members ommitted):
public interface IGraph { }
attribute to decorate the appropriate classes for factory assigment
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false,Inherited=true)]
public class GraphTypeAttribute : System.Attribute
{ public GraphTypeAttribute(string friendlyName) { } }
the classes decorated with the attribute
[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 advise on the class is thankfully appreciated.