Friday, September 11, 2009

InternalsVisibleToAttribute (C#)

Today I am going to give an idea on internal visible attribute which was introduced in .NET 2.0. This feature is better than accessing non-public member using reflection. Before starting this topic it is better to take a look on the different access modifier available in C# which will give us a clear picture on this.

Access Modifiers:
-Public
The type or member can be accessed by any other code in the same assembly or another assembly that references it.

-Private
The type or member can only be accessed by code in the same class or struct.

-Protected
The type or member can only be accessed by code in the same class or struct, or in a derived class.

-Internal
The type or member can be accessed by any code in the same assembly, but not from another assembly.

-Protected Internal
The type or member can be accessed by any code in the same assembly, or by any derived class in another assembly.

Friend Assemblies:

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.

It is better to give an example to understand better:
1. Add a class libarary (with name 'A')
Code will looks:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace A
{

public class Class1
{
private int num1 = 1;
public int num2 = 2;
protected int num3 = 3;
internal protected int num4 = 4;
int num5 = 5;
}
}

2. Add another console application (With name 'B') bellow
3. Add the project reference 'A' to project 'B' and add the below code to program.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using A;

namespace B
{
class Program
{
static void Main(string[] args)
{
Class1 obj = new Class1();
int n1 = obj.num1; //Compiler error
int n2 = obj.num2; //No error
int n3 = obj.num3; //Compiler error
int n4 = obj.num4; //Compiler error
int n5 = obj.num5; //Compiler error
}
}
}

3. Compile the both the project and watch carefully. We are able to access only num2 as its access modifier is public. Don't worry we will do some this which will allow to access num4
4. Add the below code line to AssemblyInfo.cs on project 'A'. which will tell the 'A' to allow 'B' to access his protected internal members
[assembly: InternalsVisibleTo("B")]
5. Now recompile the project and you will see:
int n1 = obj.num1; //Compiler error
int n2 = obj.num2; //No error
int n3 = obj.num3; //Compiler error
int n4 = obj.num4; //No error
int n5 = obj.num5; //Compiler error



We can also provide the public token key whiling specifying the assembly name to the assemblyinfo.cs. To do this you may need following:

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.

Example:
[assembly:InternalsVisibleTo("B, PublicKey=002400000480000094…")]

Enjoy..:):)

1 comment: