How to: Create unsigned friend assemblies

This example shows how to use friend assemblies with assemblies that are unsigned.

Create an assembly and a friend assembly

  1. Open a command prompt.

  2. Create a C# or Visual Basic file named friend_unsigned_A that contains the following code. The code uses the InternalsVisibleToAttribute attribute to declare friend_unsigned_B as a friend assembly.

    // friend_unsigned_A.cs
    // Compile with:
    // csc /target:library friend_unsigned_A.cs
    using System.Runtime.CompilerServices;
    using System;
    
    [assembly: InternalsVisibleTo("friend_unsigned_B")]
    
    // Type is 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");
        }
    }
    
    ' friend_unsigned_A.vb
    ' Compile with:
    ' vbc -target:library friend_unsigned_A.vb
    Imports System.Runtime.CompilerServices
    Imports System
    
    <Assembly: InternalsVisibleTo("friend_unsigned_B")>
    
    ' Friend type.
    Friend Class Class1
        Public Sub Test()
            Console.WriteLine("Class1.Test")
        End Sub
    End Class
    
    ' Public type with Friend member.
    Public Class Class2
        Friend Sub Test()
            Console.WriteLine("Class2.Test")
        End Sub
    End Class
    
  3. Compile and sign friend_unsigned_A by using the following command:

    csc /target:library friend_unsigned_A.cs
    
    vbc -target:library friend_unsigned_A.vb
    
  4. Create a C# or Visual Basic file named friend_unsigned_B that contains the following code. Because friend_unsigned_A specifies friend_unsigned_B as a friend assembly, the code in friend_unsigned_B can access internal (C#) or Friend (Visual Basic) types and members from friend_unsigned_A.

    // friend_unsigned_B.cs
    // Compile with:
    // csc /r:friend_unsigned_A.dll /out:friend_unsigned_B.exe friend_unsigned_B.cs
    public class Program
    {
        static void Main()
        {
            // Access an internal type.
            Class1 inst1 = new Class1();
            inst1.Test();
    
            Class2 inst2 = new Class2();
            // Access an internal member of a public type.
            inst2.Test();
    
            System.Console.ReadLine();
        }
    }
    
    ' friend_unsigned_B.vb
    ' Compile with:
    ' vbc -r:friend_unsigned_A.dll friend_unsigned_B.vb
    Module Module1
        Sub Main()
            ' Access a Friend type.
            Dim inst1 As New Class1()
            inst1.Test()
    
            Dim inst2 As New Class2()
            ' Access a Friend member of a public type.
            inst2.Test()
    
            System.Console.ReadLine()
        End Sub
    End Module
    
  5. Compile friend_unsigned_B by using the following command.

    csc /r:friend_unsigned_A.dll /out:friend_unsigned_B.exe friend_unsigned_B.cs
    
    vbc -r:friend_unsigned_A.dll friend_unsigned_B.vb
    

    The name of the assembly that is generated by the compiler must match the friend assembly name that is passed to the InternalsVisibleToAttribute attribute. You must explicitly specify the name of the output assembly (.exe or .dll) by using the /out compiler option. For more information, see /out (C# compiler options) or -out (Visual Basic)..

  6. Run the friend_unsigned_B.exe file.

    The program outputs two strings: Class1.Test and Class2.Test.

.NET security

There are similarities between the InternalsVisibleToAttribute attribute and the StrongNameIdentityPermission class. The main difference is that StrongNameIdentityPermission can demand security permissions to run a particular section of code, whereas the InternalsVisibleToAttribute attribute controls the visibility of internal or Friend (Visual Basic) types and members.

See also