Overview
We will accomplish building reusability into our project by exposing the interfaces to our objects publicly while hiding the implementation in an assembly containing only internal classes and then exposing the interfaces to our classes in a "builder" assembly. The builder assembly will be the only assembly allowed to make instances of the core objects so the instantiation of our objects are effectively hidden and not available outside the builder classes.
Project Core
For this project we will build a simple Money object that can be added. Our four assemblies will consist of
- FriendlyTesting.Core: Contains our interface definitions.
- FriendlyTesting.Hidden: Contains our implementation in classes internal to this assembly.
- FriendlyTesting.Friend: Exposes instantiation of the internal classes in FriendlyTesting.Hidden.
- FriendlyTesting.TestHarness: The final test harness console project.

Interfaces
Our interfaces define an IMoney interface that is IAddable<IMoney> (so we can add up our money in the test harness).

Concrete Implementation
The internal Money class implements IMoney and is "hidden" because it can only be instantiated from inside the containing assembly or a friend assembly.

Builders
The builder class will implement an interface specific to the builder: IMoneyMaker. The builder's responsibility is to instantiate the Money object and expose it through the IMoney interface.

Our solution
The first thing to note is that the Money is hidden in it's assembly because it is marked as internal.
internal class Money: IMoney, IAddable<IMoney>
As a result, from our money builder class, the money is not available because the Money class is only internally available to the FriendlyTesting.Hidden assembly. As a result, we can not instantiate a Money object until we make the FriendlyTesting.Friend assembly a "friend" of the FriendlyTesting.Hidden assembly indicating that it can be trusted with the internal classes.
public class MoneyBuilder: IMoneyMaker
{
#region IMoneyMaker Members
public IMoney MakeMoney(double amount)
{
// Money is not available here...
// it is internal to FriendlyTesting.Hidden
}
#endregion
}
Creating a Friendly Assembly
Our goal is to make instantiation possible only through our builder class, so in the next few steps we'll make these two assemblies play nicely with each other.
Step 1) Strongly Naming the Assemblies
The first step is to make all the assemblies strong named. So we will create keys for our two assemblies (friend and hidden) through the "sn" visual studio command line utility (Start>Programs>Visual Studio>Visual Studio Tools>Visual Studio Command Prompt).
Command line syntax:
sn -k <new key name>
Actual command:
sn -k FriendlyKey.snk
Generating the key for the FriendlyTesting.Friend assembly:

Generating the key for the FriendlyTesting.Hidden assembly:

Because these two assemblies are strongly named, all referenced assemblies also have to be strongly named, so we'll do the same thing for the FriendlyTesing.Core assembly that holds our core interface definitions.
Step 2) Add the Keys to the Projects
Now we have to add the keys we generated to their respective projects through the project's properties (right click on the project and select 'Properties'). We'll walk through this for the FriendlyTesting.Friend assembly:

Click "Sign the assembly" and select browse from the drop down that is activated.
Open FriendKey.snk and it will now appear in our project

Add HiddenKey.snk to the friendlyTesting.Hidden project and the core key to the core project in the same way.

Step 3) Extract public key for friend assembly
Next we will extract the public key from our FriendlyKey.snk (the key for the FriendlyTesting.Friend project). We need information from the public key in order to let the hidden project know which assemblies to be friendly with. We will generate a new public key called "FriendlyKey_public.snk" with the following command:


Join the conversation! Your thoughts help the community grow.