Scenario:
Assembly MyLib contiene due tipi: public A  e internal B (Friend in VB).
Assembly MyExe che utilizza MyLib.
Immaginiamo ora di avere necessità di accedere da MyExe anche al tipo B (ad esempio perchè vogliamo sottoporlo a Unit Testing) quali soluzioni abbiamo a disposizione?, ovviamente quella di rendere publico B il che però potrebbe, in svariati casi, essere qualcosa che vogliamo evitare.
Al momento una parziale soluzione ci viene data dall'attributo
StrongNameIdentityPermission grazie al quale possiamo essere "sicuri" che solo una determinata assembly (in questo caso MyExe) possa utilizzare il tipo B malgrado la sua interfaccia sia publicamente visibile, ovvero, se MyExe ha uno strong name, possiamo decorare la classe B con:

[StrongNameIdentityPermission(SecurityAction.Demand,
PublicKey="00240000048000009400000006020000"
+
                    "00240000525341310004000001000100"
+
                    "6132A2C85314ED770DBD76B71E5F3E4A"
+
               "BBE2F88B49BFE78ACA431D4D75FDCBE9"
+
               "7911CB9D6619F1E426DB2AC09D160F40"
+
               "4EDDF059D4DD292AF21176CF3BE52F56"
+
               "43F917562B0FAE6E24CAAA1EEF13FE43"
+
               "7BD17B32484436F5DCDEF90E90A04ADC"
+
               "B29110080EBC4A5238A24C0BB7C7BC74"
+
               "D1CD329121273EE92BB5836032ACC4DB"
)]
public class
B
{
  public int
Calc()
  {
     return 1
;
  }
}
Questa tecnica ha parecchi svantaggi:

  • Se le classi da esporre sono parecchie dobbiamo decorare ognuna di esse con l'attributo StrongNameIdentityPermission
  • Il tutto funziona se l'assembly chiamante non è full trusted in quanto ogni chiamante fulltrust può disabilitare la CAS usando SecurityManager.SecurityEnabled=false
  • Nel framework 2.0, se il chiamante è full trusted l'attributo viene automaticamente ignorato (dettagli qui)

Per questo genere di necessità il framework 2.0 offre un alternativa più elegante ovvero le cosidette Friend Assemblies.
Ritornando al nostro esempio, volendo esporre il tipo interno B esclusivamente a MyExe, possiamo aggiungere a MyLib questo attributo:

[assembly: InternalsVisibleTo("MyExe, PublicKeyToken=5286e76b09aa94aa")]  //PublicKeyToken è il PublicKeyToken di MyExe

In questo modo MyExe avrà accesso a tutti i tipi interni di MyLib in quanto InternalVisibleTo agisce a livello di Assembly, il tutto viene confermato dall' Intellisense di Visual Studio 2005 il quale elenca correttamente tutti i tipi divenuti ora "friend".

Qualche nota:

  • La visibilità è unidirezionale ovvero se B è Friend Assembly di A, A non è automaticamente Friend Assembly di A
  • Se C è "friend" di B, e B è "friend" di A, C non è automaticamente "friend" di A.