Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
We have a feature in C# which allows you to declare a "friend assembly". If assembly Smith says that assembly Jones is its friend, then code in Jones is allowed to see "internal" types of Smith as though they were public(*). It's a pretty handy feature for building a "family" of assemblies that share common implementation details.
The compiler enforces one particularly interesting rule about the naming of friendly assemblies. If assembly Smith is a strong-named assembly, and Smith says that assembly Jones is its friend, then Jones must also be strong-named. If, however, Smith is not strong-named, then Jones need not be strong-named either.
I'm occasionally asked "what's up with that?"
When you call a method in Smith and pass in some data, you are essentially trusting Smith to (1) make proper use of your data; the data might contain sensitive information that you don't want Smith to misuse, and (2) take some action on your behalf. In the non-computer world an entity which you share secrets with and then empower to take actions on your behalf is called an "attorney" (**). That got me thinking, which usually spells trouble.
You want to hire an attorney. You go to Smith & Jones, Esqs. You meet with Smith, the trustworthy-looking man on the left of this photo:
You check Smith's ID. It really is Mel Smith. You are contemplating giving Smith a secret, and empowering Smith to act on your behalf with the knowledge of that secret. Smith says "I share my secrets with my partner Griff Rhys Jones, whose identity you may now verify, here is Jones and here is Jones' ID. Jones will also be acting on your behalf. Jones has full access to all secrets which are internal to this organization."
You decide that you trust both Smith and Jones, so you share your secrets with Smith. A series of wacky sketch comedy hijinks then ensues.
(Smith and Jones are both strong-named assemblies. That is, they have "ID" you can verify. Smith's internals are visible to Jones. Everything is fine.)
You check the ID. It is Mel Smith. Smith says "By the way, I share my internal secrets with everyone in the world who claims their name is Jones, I don't bother to check IDs, I just trust 'em, and you should too! Everyone named Jones is trustworthy! Oh, and that includes my partner over here, Jones. Good old Jones! No, you can't check Jonesie's ID. Doesn't have any ID, that Jones."
This is ludicrous. Obviously this breaks the chain of trust that you showed you were looking for when you checked Smith's ID in the first place.
(The compiler keeps you from getting into this terrible situation by preventing Smith from doing that; Smith, a strong-named assembly, can only state that it is sharing his internal details with another strong-named assembly. Smith cannot share its internals with any assembly named Jones, a weakly-named assembly in this scenario. We restrict Smith from exposing internals to weakly-named assemblies so that Smith does not accidentally create this security hole or accidentally mislead you into believing that Smith's internals are in any way hidden from partially-trusted code.)
You don't bother to check Smith's ID. In fact, you give your secrets and power of attorney to anyone named Smith, regardless of who they actually are or where they came from. The first Smith you pick off the street says "By the way, I'll give my internal secrets to anyone named Jones".
Do you care? Why would you? You're already giving secrets away to anyone named Smith! If a con artist wants your secrets, he can pretend to be Jones and take them from Smith, or he can pretend to be Smith and get them from you directly, but either way, the problem is that you are giving away secrets and power of attorney to strangers off the street.
(Smith and Jones are both weakly named assemblies, Smith exposes internals to Jones. This is perfectly legal, because if you don't care enough about who you're talking to to check IDs then what's the point of the security system preventing those random strangers from talking to each other?)
**************(*) Fully trusted assemblies of course can always use reflection to see private and internal details of other assemblies; that is what "full trust" means. And in the new CLR security model, two assemblies that have the same grant set can see each other's private and internal details via reflection. But friend assemblies are the only mechanism that allow compile time support for peering at the internal details of another assembly.
(**) or "delegate", which obviously I want to avoid because that means something technical in C#.
I've never needed to use friend assemblies. It breaks encapsulation, which is a no-no. At least you have to be explicit (in the case of strongly-named assemblies) in who can access the internals, but it still smells to me.
> It breaks encapsulation, which is a no-no.
It doesn't break encapsulation any more than "internal" does on its own. It simply defines another encapsulation boundary, which you still fully control (especially when it comes to signed assemblies).
1) How is this different than InternalsVisibleToAttribute? [Which I typcially use only for UnitTesting access]
2) Exposing internals across an assembly boundary is philosophically to using "partial" to expose class internals across a file boundary.
Pardon the first question, I had not followed the link abnd though this blog was about a NEW (aka .net 4.0) feature, rather than something that has been around for YEARS!!!!!
A good way of expressing it, as always.
Now if only the syntax for InternalsVisibleTo were prettier - perhaps using the public key *token* rathen than the full key...
@KodefuGuru: I've found it actually improves encapsulation, by allowing you to mark some things as internal that would otherwise need to be given greater access to allow for unit testing.
I love how you used Smith and Jones in this article :-)
I didn't know you guys over in the US knew who Smith and Jones are. I'm from the UK and grew up with them on TV, they're awesome aren't they :-)
I didn't think I'd ever see them used to illustrate a programming related concept, kudos to you sir ;-)
My introduction to Smith and Jones was the London Weekend Television adaptation of "Wilt", which was a favourite novel of mine in my younger days. Jones completely nails the character of Wilt. -- Eric
"We restrict Smith from exposing internals to weakly-named assemblies so that Smith does not accidentally create this security hole or accidentally mislead you into believing that Smith's internals are in any way hidden from partially-trusted code."
IMO, the chain of trust of strong naming is a mistake. Nothing prevents that Smith gives away a key so that anybody can build a Jones account. I asked this here http://stackoverflow.com/questions/868799/why-cant-strongly-named-assemblies-use-assemblies-that-arent-signed
@jcoehoorn: +1. Unit tests often need to test things otherwise marked as private or internal, and contorting the design or the visibility for the sake of enabling a unit test seems unnecessary. (I know some people believe that you should only unit test public interfaces, but when they rely on sufficiently interesting private information, the goal of confirming correct behaviors and states is greatly simplified, and therefore more cheaply and correctly performed, by testing private methods and asserting on private properties/member variables as well.) As stated, friend assemblies don't seem to solve the problem of unit-testing private methods, but it will help a great deal nonetheless.
It has always struck me that public, private, protected, internal are simply coarse access control mechanisms, and for ORM and unit-testing purposes we would benefit from finer-grain access control.
Is it wrong that I first read the title of this post as "Alias, Smith and Jones" (like the old TV show)?
No, not at all. Smith and Jones named their comedy show "Alas Smith and Jones" as a pun on "Alias Smith and Jones" -- Eric
I find the InternalsVisibleTo attribute extremely useful for n-Tier solutions, especially those with interchangeable assemblies providing interop with different database servers or other external solutions.
The thing I'd really like would be GUI support for it in VS 2010. Many of the AssemblyInfo.cs attributes are exposed in the Project Properties pages, so why not InternalsVisibleTo? Especially useful for the strongly-named assemblies.
Welcome to the 49th edition of Community Convergence. The big excitment of late has been the recent release
В C# есть возможность объявить « дружественную сборку ». Если сборка Смит говорит, что сборка Джонс –
Mel Smith's career didn't last much longer than the TV series, Griff Rhys Jones however is still everywhere on the BBC.
I've found InternalsVisible great for whitebox testing, if you're a believer in that.