我实际上正在做这样的事情。如果它们存在/将工作,则对程序集进行了探测。
当然,您可以通过多种方式做到这一点,但这就是我的结尾:
- 将此类的所有功能提取到接口中(我们称之为:IExcel)并为其添加 IsAvailable 属性
- 实现了实现 IExcel 的假类,并从 IsAvailable 返回“false”(当然,从其他方法抛出 NotSupportedException)。
- 使用 IExcel 的实际实现创建新程序集(重要:新程序集)
- 使用“Create”实现 Factory 类,它将决定应该返回哪一个并在解析(或测试)时捕获异常
组装:MyFacade
// the interface
public interface IExcel
{
bool IsAvailable { get; }
// your stuff
}
// the fake implementation
public class FakeExcel: IExcel
{
public IsAvailable { get { return false; } }
// your stuff should probalby throw NotSupportedException
}
组装:MyImplementation
// real implementation
public class RealExcel: IExcel
{
private bool? _isAvailable;
public bool IsAvailable
{
// return value if it is already known, or perform quick test
get { return (_isAvailable = _isAvailable ?? PerformQuickTest()); }
}
private bool PerformQuickTest()
{
try
{
// ... do someting what requires Excel
// it will just crash when it cannot be found/doesn't work
}
catch // (Exception e)
{
return false;
}
return true;
}
}
组装:MyFacadeFactory
public class ExcelFactory
{
public static IExcel Create()
{
// delay resolving assembly by hiding creation in another method
return Try(NewRealExcel) ?? new FakeExcel();
}
private static IExcel Try(Func<IExcel> generator)
{
try
{
var result = generator();
if (result.IsAvailable)
return result;
}
catch // (Exception e)
{
// not interested
}
return null; // didn't work exception or IsAvailable returned 'false'
}
// this could be implemented as delegate but it's
// safer when we put NoInlining on it
[MethodImpl(MethodImplOptions.NoInlining)]
private static IExcel NewRealExcel()
{
return new RealExcel();
}
}
会发生什么?
- 如果你有 Excel 并且可以找到 MyImplementation 程序集,它将被加载,RealExcel 类将被创建然后使用
- 如果您没有 Excel 但确实有 MyImplementation 程序集,它将被加载,将创建 RealExcel 类,但在“PerformQuickTest”上将失败,因此将使用 FakeExcel
- 如果在 MyFacade 中创建 RealExcel 时找不到 MyImplementation 程序集(您没有包含它),它将失败,因此将使用 FakeExcel
您当然可以通过动态加载和反射(更少的代码行)来完成所有这些事情,但使用起来有点笨拙。我发现这种方法反射最少。