问题
I am trying to write a small c#/.net library for very specific financial calculations.
I have written several classes that depend only on the standard assemblies of the .net framework. That is, the library with these classes require nothing other than the .net framework (4.0 client).
Now I need an additional class for excel integration. This class will require additional assembly references related with microsoft office and excel, like their respective object libraries.
My problem is: Some of the users of this library may have office and excel, some not.
How can I add this additional class to the library so that both types of users can use the library without getting errors?
More precisely: If a user does not have office and excel, user must be able to run all the classes excluding excel-related one without getting errors.
thanks for any help, selmar
回答1:
I was actually doing something like this. Assemblies were probed if they exist/will work.
You can do this in many ways, of course, but that's what I ended with:
- Extracted all the functionality of this class into interface (let's call it: IExcel) and added IsAvailable property to it
- Implemented fake class implementing IExcel, and returning 'false' from IsAvailable (and, of course, throwing NotSupportedException from other methods).
- Create new assembly (important: NEW ASSEMBLY) with real implementation of IExcel
- Implement Factory class with 'Create' which will decide which one should be returned and catch exception on resolve (or test)
Assembly: 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
}
Assembly: 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;
}
}
Assembly: 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();
}
}
What will happen?
- If you have Excel and MyImplementation assembly can be found, it will be loaded, RealExcel class will be created and then used
- If you don't have Excel but you do have MyImplementation assembly, it will be loaded, RealExcel class will be created, but will fail on 'PerformQuickTest' so FakeExcel will be used
- If MyImplementation assembly cannot be found (you did not include it) it will fail when RealExcel is created in MyFacade, so FakeExcel will be used
You can of course do all those things with dynamic loading and reflection (less lines of code) but a little bit clunky to use. I've found this method most reflection-less.
回答2:
This should work out of the box. Assemblies are loaded on demand, i.e. they are loaded when needed. As long as the users without Excel are not using the Excel related class there should be no error.
回答3:
Did you try ILMerge ? This will enable you to add the required dll to your executable so you'll be sure that the user has the required assemblies
来源:https://stackoverflow.com/questions/16343506/how-to-check-programatically-if-an-assembly-reference-exists-in-c