Adapter Pattern
One of the strengths of the .NET Framework is backward compatibility. From .NET-based code you can easily call legacy COM objects and vice versa. In order to use a COM component in your project, all you have to do is add a reference to it via the Add Reference dialog in Visual Studio .NET. Behind the scenes, Visual Studio® .NET invokes the tlbimp.exe tool to create a Runtime Callable Wrapper (RCW) class, contained in an interop assembly. Once the reference has been added (and the interop assembly has been generated for you), the COM component can be used like any other class in managed code. If you were looking at code someone else had written without seeing the list of references (and without examining metadata associated with the classes or their implementation), you would be unable to tell which classes were written in a .NET-targeted language and which were COM components.
The magic that makes this happen is contained in the RCW. COM components have different error handling mechanisms and also make use of different data types. For example, strings in the .NET Framework use the System.String class while COM might use a BSTR. When calling a COM component with a string parameter from .NET-based code, though, you can pass in a System.String just like you would to any other similar managed code method. Inside the RCW, this System.String is converted into a format that the COM component expects, like a BSTR, before the COM call is made. Similarly, a method call on a COM component typically returns an HRESULT to indicate success or failure. When a COM method call returns an HRESULT that indicates that the call failed, the RCW turns this into an exception (by default), so it can be handled like all other managed code errors.
By allowing managed classes and COM components to interact despite their interface differences, RCWs are an example of the Adapter pattern. The Adapter pattern lets you adapt one interface to another. COM doesn’t understand the System.String class, so the RCW adapts it to something that it can understand. Even though you can’t change how a legacy component works, you can still interact with it. Adapters are frequently used like this.
The Adapter class itself wraps an Adaptee, translating all calls from the client into the appropriate format and sequence of calls. Though this sounds similar to the Decorator, there are several key differences. With a Decorator, the interfaces of the objects you’re composing are the same, while the entire point of an Adapter is to allow you to change interfaces.Adapters also have a definite sequence to them; the Adaptee must be contained by the Adapter. A Decorator class doesn’t need to know whether it is wrapped by 1 or 500 other classes, since the interfaces are all the same. As a result, the use of Decorators can be transparent to the application, while the use of Adapter cannot.
