My .net program is using an assembly, which should be installed in the GAC.
If the assembly is properly installed, it will be loaded as soon as I use it the first time, which is great. If, for example, I use a type from the assembly like this:
ESRI::ArcGIS::esriSystem::AoInitialize^ aoi = gcnew ESRI::ArcGIS::esriSystem::AoInitializeClass();
The assembly will be loaded.
Now sometimes the assembly will not be present in the GAC, and I need the program to be aware of this but not crash.
I tried wrap开发者_如何学编程ping the usage of the assembly into a try/catch block like this:
try
{
ESRI::ArcGIS::esriSystem::AoInitialize^ aoi = gcnew ESRI::ArcGIS::esriSystem::AoInitializeClass();
}
catch (System::Exception^ )
{
// assembly not found
}
But the program will not throw an exception but crash instead.
How can I check in advance, if the assembly is in the GAC and could be used without crashing? Or how could I catch the crash and disable the corresponding menu items in my program?
You have the wrong mental model about the way assemblies get loaded. It does not happen when you create an instance of a type in the assembly. The JIT compiler is the one that needs the assembly first. To generate the machine code for the method. If you look at the call stack for the exception then you'll see that the exception was raised in the calling method.
At least, that's what normally happens when you use a Microsoft jitter, it generates machine code on demand, at the last possible moment. It is different for other jitters, like the Mono one, it compiles much more eagerly.
You could catch the exception in the calling method but that's pretty brittle. Other than the jitter dependency, you will also have to attribute the method with [MethodImpl(MethodImplOptions.NoInlining)] to ensure that this code never gets inlined. Because that will again cause the type to be needed too soon.
The proper fix is to use a plug-in architecture. You have to use an interface type to declare the properties and methods you'll want to use in your main program. That interface type needs to be declared in a separate assembly, reference by both your main program and the plugin. And deployed with your main program, whether or not the plugin option is available to your customer. Use Assembly.Load() to load the plugin assembly and Assembly.CreateInstance() to create the concrete instance of the type that implements the interface. And never refer to the concrete type in your code, only the interface type. You'll find lots of examples of this with a google query.
The best way would be to add all the necessary assemblies in the installation process.
However, what you want can be achieved with a simple type check before creating the type.
Something like this:
var t = System.Type.GetType("TypeName, Assembly");
if (t == null) throw CannotLoadTypeException();
精彩评论