Friend Assemblies (C# Programming Guide)

An internal type or internal member in an assembly can be accessed from another assembly.

Remarks

The friend assemblies feature allows you to access internal members; private types and private members will remain inaccessible.

To give an assembly (assembly B) access to another assembly's (assembly A's) internal types and members, use the InternalsVisibleToAttribute attribute in assembly A.

Note

When compiling an assembly (assembly B) that will access internal types or internal members of another assembly (assembly A), you must explicitly specify the name of the output file (.exe or .dll) with the /out compiler option (see /out for more information). This is required because the compiler has not yet generated the name for the assembly it is building at the time it is binding to external references.

The StrongNameIdentityPermission class also provides the ability to share types, with the following differences:

  • StrongNameIdentityPermission applies to an individual type, while a friend assembly applies to the whole assembly.

  • If there are hundreds of types in assembly A that you wish to share with assembly B, you have to decorate all of them with StrongNameIdentityPermission, while using a friend assembly, you only need to declare the friend relationship once.

  • Using StrongNameIdentityPermission, the types you want to share have to be declared as public. Using a friend assembly, the shared types are declared as internal.

  • For information on how you can build a .netmodule that can access non-public types in an assembly, see /moduleassemblyname.

Example

In this example, the assembly makes internal types and internal members visible to the assembly called cs_friend_assemblies_2.

// cs_friend_assemblies.cs
// compile with: /target:library
using System.Runtime.CompilerServices;
using System;

[assembly:InternalsVisibleTo("cs_friend_assemblies_2")]

// internal by default
class Class1 
{
    public void Test() 
    {
        Console.WriteLine("Class1.Test");
    }
}

// public type with internal member
public class Class2 
{
    internal void Test() 
    {
        Console.WriteLine("Class2.Test");
    }
}

In this example, the assembly consumes internal types and internal members in assembly cs_friend_assemblies.dll.

Notice that you must explicitly specify the name of the output file (/out:cs_friend_assemblies_2.exe).

If this assembly gives another assembly (assembly C) access to its internal types and members, assembly C does not automatically become a friend of assembly cs_friend_assemblies.dll.

// cs_friend_assemblies_2.cs
// compile with: /reference:cs_friend_assemblies.dll /out:cs_friend_assemblies_2.exe
public class M 
{
    static void Main() 
    {
        // access an internal type
        Class1 a = new Class1();
        a.Test();

        Class2 b = new Class2();
        // access an internal member of a public type
        b.Test();
    }
}

Class1.Test Class2.Test

This example shows how to make internal types and members available for assemblies that have strong names.

To generate the keyfile and display public key, use the following sequence of sn.exe commands (for more information, see Strong Name Tool (Sn.exe)):

  • sn -k friend_assemblies.snk // Generate strong name key

  • sn -p friend_assemblies.snk key.publickey // Extract public key from key.snk into key.publickey

  • sn -tp key.publickey // Display public key stored in file'key.publickey

Pass the keyfile to the compiler with /keyfile.

// cs_friend_assemblies_3.cs
// compile with: /target:library /keyfile:friend_assemblies.snk
using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("cs_friend_assemblies_4, PublicKey=0024000004800000940000000602000000240000525341310004000001000100031d7b6f3abc16c7de526fd67ec2926fe68ed2f9901afbc5f1b6b428bf6cd9086021a0b38b76bc340dc6ab27b65e4a593fa0e60689ac98dd71a12248ca025751d135df7b98c5f9d09172f7b62dabdd302b2a1ae688731ff3fc7a6ab9e8cf39fb73c60667e1b071ef7da5838dc009ae0119a9cbff2c581fc0f2d966b77114b2c4")]
class Class1 
{
    public void Test() 
    {
        System.Console.WriteLine("Class1.Test");
    }
}

This example shows how to consume internal types and members available for assemblies that have strong names.

// cs_friend_assemblies_4.cs
// compile with: /keyfile:friend_assemblies.snk /reference:cs_friend_assemblies_3.dll /out:cs_friend_assemblies_4.exe
public class M 
{
    static void Main() 
    {
        Class1 a = new Class1();
        a.Test();
    }
}

Class1.Test

See Also

Concepts

C# Programming Guide

Reference

Assemblies and the Global Assembly Cache (C# Programming Guide)