How to: Diagnose and Fix Assembly Compatibility Problems (C++/CLI)
The latest version of this topic can be found at How to: Diagnose and Fix Assembly Compatibility Problems (C++/CLI).
This topic explains what can happen when the version of an assembly referenced at compile time doesn't match the version of the assembly referenced at runtime, and how to avoid the problem.
When an assembly is compiled, other assemblies may be referenced with the #using
syntax. During the compilation, these assemblies are accessed by the compiler. Information from these assemblies is used to make optimization decisions.
However, if the referenced assembly is changed and recompiled, and you do not recompile the referencing assembly that is dependent on it, the assemblies might not still be compatible. Optimization decisions that were valid at first might not be correct with respect to the new assembly version. Various runtime errors might occur due to these incompatibilities. There is no specific exception that will be produced in such cases. The way the failure is reported at runtime depends on the nature of the code change that caused the problem.
These errors should not be a problem in your final production code as long as the entire application is rebuilt for the released version of your product. Assemblies that are released to the public should be marked with an official version number, which will ensure that these problems are avoided. For more information, see Assembly Versioning.
Diagnosing and fixing an incompatibility error
If you encounter runtime exceptions or other error conditions that occur in code that references another assembly, and have no other identified cause, you may be dealing with an out of date assembly.
First, isolate and reproduce the exception or other error condition. A problem that occurs due to an outdated exception should be reproducible.
Check the timestamp of any assemblies referenced in your application.
If the timestamps of any referenced assemblies are later than the timestamp of your application's last compilation, then your application is out of date. If this occurs, recompile your application with the most recent assembly, and make any code changes required.
Rerun the application, perform the steps that reproduce the problem, and verify that the exception does not occur.
Example
The following program illustrates the problem by reducing the accessibility of a method, and trying to access that method in another assembly without recompiling. Try compiling changeaccess.cpp
first. This is the referenced assembly which will change. Then compile referencing.cpp
. The compilation succeeds. Now, reduce the accessibility of the called method. Recompile changeaccess.cpp
with the flag /DCHANGE_ACCESS
. This makes the method protected, rather than private, so it can longer be called legally. Without recompiling referencing.exe
, rerun the application. An exception MethodAccessException will result.
// changeaccess.cpp
// compile with: /clr:safe /LD
// After the initial compilation, add /DCHANGE_ACCESS and rerun
// referencing.exe to introduce an error at runtime. To correct
// the problem, recompile referencing.exe
public ref class Test {
#if defined(CHANGE_ACCESS)
protected:
#else
public:
#endif
int access_me() {
return 0;
}
};
// referencing.cpp
// compile with: /clr:safe
#using <changeaccess.dll>
// Force the function to be inline, to override the compiler's own
// algorithm.
__forceinline
int CallMethod(Test^ t) {
// The call is allowed only if access_me is declared public
return t->access_me();
}
int main() {
Test^ t = gcnew Test();
try
{
CallMethod(t);
System::Console::WriteLine("No exception.");
}
catch (System::Exception ^ e)
{
System::Console::WriteLine("Exception!");
}
return 0;
}