下面的代码是一个工厂类,它传递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());
}
}