Coding With .NET Proxy Types
A Brief History Lesson
Java started out as a language that addressed the perceived (and real) weaknesses of C++ in the areas of complexity, memory management, and library functionality. Many people thought that it was just too easy to write buggy code in C++. Pointers, memory management, and advanced preprocessor features were identified as some of the main culprits and Java simply did away with them.
At the same time, Java's inventors added a lot of library types
that provided built-in functionality that most C++ developers would have killed for in 1999. A lot of the more advanced features that
C++ developers rely on today (templates, operator overloading, the entire
std library, boost, etc.) were not yet available
to C++ developers in the early years of Java.
While the original Java vision had been to create a language for the browser—Java applets was seen as the killer app—it soon became obvious that the real strength of Java lay in the back office. The promise of "write once, run anywhere" was very appealing to server programmers who had to maintain multiple versions of their software to run on different operating systems. Platform independence became Java's killer feature.
Microsoft rightly felt threatened by this trend. The huge ecosystem of Windows-only applications was a major reason for its dominance on the desktop and Java threatened to reduce the platform lock-in. Microsoft was working hard to extend its dominance to servers and Java threatened the whole game plan. So .NET and J# were invented to give people an "almost-Java" experience while maintaining lock-in to Windows.
But to just label .NET Microsoft's "Java killer" would be unfair. Its architects were highly capable engineers who came up with their own ideas. While Sun Microsystems pitched Java as the solution to platform interoperability, Microsoft pitched .NET as the solution to language interoperability. .NET promised to unify the cross-language experience on Windows while Java promised to unify the cross-platform experience on all major platforms. Both were trying to solve a problem that was near and dear to their hearts.
It could have been a match made in heaven, yet the two just would not work together to create a unified experience because that would have weakened their competitive positions.
Proxy Types to the Rescue
Codemesh tackled Java/.NET interoperability just a few months after .NET became available. At first, J# was available and people asked why they should use an awkward bridge technology rather than J#. Then Microsoft deprecated J# and it became painfully obvious that Java was not going to be a part of Microsoft's unified language world. Codemesh's proxy type-based solution became an important tool for many enterprises and has remained so for almost two decades.
In general, the .NET proxy types are as usage-compatible with their corresponding Java types as we can make them. This means that you can take an application that is written in Java and replicate it by writing .NET code that is almost a one-to-one mirror image of the Java code.
This is made possible by Java and C# being, in general, very similar and both languages having an escape hatch in the form of JNI for Java and P/Invoke for .NET.
A .NET proxy type for a Java type is much more than just a .NET type that has the same name as its underlying Java type: it has the expected type inheritances; it has properties that can be used as fields without having to worry about the lifecycle of returned objects; it has methods that take strongly-typed arguments and return strongly-types results; it has framework constructors, and much more to make sure that the proxy type can be used just as you would expect.
We encourage you to go through the tutorial and maybe also the pitfalls page to get a feeling for what it is like to write .NET code using proxy types.