I like to make sure that the members of the types (and the types themselves) that I define are only available to the types that need it. This is done by providing the appropriate scope. C# and VB.Net define 5 possible scopes – public, private, protected, internal (friend in VB) and internal protected (protected friend in VB). I’ll give a brief background on each so if you already know this stuff you can skip ahead:
Public
Public members are visible to all types whether they are defined in the same assembly or within another assembly. So given a class A, anyone that has an instance of A can call its Foo method.
public class A
{
public void Foo() {}
}
Protected
Protected is sometimes referred to as Family in the CLR documentation. Basically protected means that only derived classes can access that member. So given a class A, only classes that derive from A can call its Foo method.
public class A
{
protected void Foo() { }
}
Private
Private members are only available within that class. So given a class A, only class A can call its Foo method.
public class A
{
private void Foo() { }
}
Assembly
Assembly scope is referred to as internal
in C# and Friend
in VB.Net. Assembly scoped members can be accessed by any type defined within the same assembly. So if you have assembly 1 with a class defined as follows, any other type defined within assembly 1 may access the Foo method but types defined in other assemblies cannot.
public class A
{
internal void Foo() { }
}
Assembly Or Protected
Assembly Or Protected combines the scopes of Assembly and Protected. In C# this would be defined as internal protected and in VB.Net the member would be defined as Protected Friend. Members with this scope can be access by any type within the same assembly or types in other assemblies that derive from this type. So if you have assembly 1 with a class defined as follows, any other type defined within assembly 1 may access the Foo method and also any type that derives from A (including types defined in an assembly other than assembly 1) may access the Foo method.
public class A
{
internal protected void Foo() { }
}
But there’s actually another scope – Assembly And Family. I used the terminology that’s used in the CLR documentation because it’s not available in C# or VB.Net. This scope is supposed to limit member access to only derived types within that assembly. Outside of that assembly or to non-derived types in the same assembly, it is as if that member doesn’t exist.
So if you have class A in assembly 1 that has a method named Foo with this scope, only classes within assembly 1 that derive from class A may access the Foo method. Personally I think this would be a useful scope to support. I even asked Jeffrey Richter at the PDC about the possibility of supporting it and he basically told me it wouldn’t happen and that I was the only person that had asked him that question. I was a little suprised by this. I spend a lot of time in reflector and there seem to be lots of cases where they could have used this type of functionality themselves.
Without this scope, you are forced to use internal instead and try to manage this via guidelines/standards. I can think of a couple of possible approaches that you could use to verify that this is the case – you could write an fxcop/static analysis rule that does the check or you could use reflection. The following method is a simple take on the latter. I’ll list the code first and then explain how it works.
public static class Utilities
{
[MethodImpl(MethodImplOptions.NoInlining)]
[Conditional(“DEBUG”)]
public static void VerifyCallerIsFamily()
{
// get the method doing the check
StackFrame sfCallee = new StackFrame(1, false);
MethodBase calleeMethod = sfCallee.GetMethod();
StackFrame sfCaller = new StackFrame(2, false);
MethodBase callerMethod = sfCaller.GetMethod();
Debug.Assert(calleeMethod.IsAssembly, “This method is meant to try and implement a scope of ‘Assembly And Family’ so the calling method should be internal.”);
if (false == calleeMethod.DeclaringType.IsAssignableFrom(callerMethod.DeclaringType))
{
const string Format = “The ‘{0}.{1}’ method is being called from ‘{2}.{3}’. It should only be called by derived types.”;
string message = string.Format(Format,
calleeMethod.DeclaringType.Name,
calleeMethod.Name,
callerMethod.DeclaringType.Name,
callerMethod.Name);
throw new InvalidOperationException(message);
}
}
}
The following will be our test scenario classes:
public class Base
{
internal void OnlyCallFromDerivedClasses()
{
Utilities.VerifyCallerIsFamily();
// do something
}
}
public class Derived : Base
{
public void VerifyCanCallMethod()
{
this.OnlyCallFromDerivedClasses();
}
}
public class NotDerived
{
public void VerifyCannotCallMethod()
{
Base b = new Base();
b.OnlyCallFromDerivedClasses();
}
}
We could then test this out:
Derived d = new Derived();
d.VerifyCanCallMethod();
NotDerived not = new NotDerived();
not.VerifyCannotCallMethod();
The call to VerifyCanCallMethod on d will pass because Derived is a derived class and has the rights to make this call. The second call will result in an exception – “The ‘Base.OnlyCallFromDerivedClasses’ method is being called from ‘NotDerived.VerifyCannotCallMethod’. It should only be called by derived types.” – which is the behavior that we want.
Ok so how does this work. The majority of the code relies upon the use of the StackFrame class to obtain the information about the method requesting the verification (the callee) and the method that is calling that method (the caller). We have to pass in 1, since this is implemented as a helper method. Passing in 0 would return the VerifyCallerIsFamily method which we do not want.
Once we have the stackframes, we can get the MethodBase instances. These are reflection objects that provide information about the method being called. We can then use the IsAssignableFrom method to ensure that the caller is either the same type as the callee or a derived class. If it is not we raise an appropriate exception.
You may notice that I decorated the VerifyCallerIsFamily with 2 attributes. The MethodImpl attribute is used to ensure that the jitter will not inline the execution of the method. The method is a little large so its unlikely that it would but its best to make sure. We need to do this because we’re relying on getting the methods using specific indexes in the stack frame. The Conditional attribute is used to indicate that calls to this method should not be included unless the code is being compiled with the DEBUG compilation constant. In other words, we only want to do this check in a debug version. My main reason for doing this is that using a StackFrame has overhead and once we release our assembly, its really not necessary to do this check since the callee method is internal and our testing can be limited to checking calls within the same assembly.
I still hope they implement that scope in a future version of C# and VB.Net but until then this approach may help you to get close.
December 15, 2007 at 5:14 am |
Andrew,
Deep, brother Deep!
Your blog will quickly get a huge following.
One problem. Mole forget to read your work and by-passes the scope attributes to display “hidden data”. 🙂
Best to you,
Karl
December 15, 2007 at 4:26 pm |
[…] Andrew Smith Random Thoughts about C#, VS, WinForms, WPF and .NET in General « Internal And Protected […]
December 15, 2007 at 5:49 pm |
Holy smokes!! This is really amazing stuff. I agree with Karl, your blog is going to develop a cult-like following if you keep this up! 🙂
Josh
December 17, 2007 at 4:45 am |
Mr Smith recently I had the same problem. What I hadn’t realized was that intentionally protected internal scope allows class that inherit my class to use the protected internal member.
I thought it was a bug. Now I realize that it is a not so good implementation in Object oriented approach. As i understand it a logic & applies to scopes.
protected allows children class to access protected members of the father
internal allows only class from the specific assebly to access specified members.
So if you apply the & bitwise logic to protectd & internal, the natural conclution is what we both expected. That’s why i first thought of it as a bug.
Personaly I believe that it is a huge problem, and being forced to used a solution like yours is not very appealing thought usefull if it comes to that.
I should not be forced to use reflection nor by any means allow the consumer of my control understand that there are members that i have made tricks to protect from accessing.
Thank you.
December 17, 2007 at 10:09 am |
Hi Alex. Actually what you are describing – internal protected – is what the clr refers to as AssemblyOrFamily (or you might think of it as InternalOrProtected). This means that the member may be accessed by someone internally in the assembly OR by any derived class even one that is in another assembly. I described this in the blurb on scopes. The scope that is not supported currently is InternalAndProtected meaning that only members that are within that assembly AND derived from the class may access the member. I agree that we should not need to use reflection to do what the compiler should be handling for us. I merely offered the reflection approach as a way to try and enforce what is not currently supported.
December 17, 2007 at 4:43 pm |
I fully understood what you explained. I just thought from my expierence that two keywords interact with the AND logic, but from what you explained I was mistaken.
Anyway thanks again for your answer.
Nice solution though.
August 8, 2011 at 11:20 am |
Years later, unfortunately still no trace of internal AND protected keyword in .NET 4. IMHO, it would be much more useful than the current internal OR protected which forbid you to set a property as protected when using an internal type!
Years of C# development behind, I wonder if I ever used “internal protected” once! (as I always though intuitively it would be AND instead of OR)
March 30, 2013 at 7:54 pm |
bonjour à tous,
Ici Melisande
Je suis une fille de trente et un années .
je suis des études de agent de maintenance ! Est-ce un défaut
d’être enjouée ?
April 18, 2013 at 1:51 am |
Je porte le joli nom de Azura.
Je suis une jeune femme de 26 berges tant pis si ça ne se dit pas .
Je suis une esthéticienne . Si je suis parfois une vraie prune,
ce n’est pas forcément un défaut ?A
April 19, 2013 at 12:00 am |
I ran into this problem while trying to make a property with a protected set in an internal class. No matter what accessor is placed on the property, if the set is protected and the class is internal then the following error is thrown:
“The accessibility modifier of the ‘PropertyName.set’ accessor must be more restrictive than the property or indexer ‘PropertyName'”
While I can see limited value for the protected OR internal (like if you are developing software libraries for resell), I also see a value for the protected AND internal. I just seems silly that the compiler does not automatically apply the internal access constraint to a protected item if its parent is internal. Sure, it might make it harder for library developers to know for sure that their property can be inherited, but if that was a big deal they could add a compiler argument to turn it on or off or add another keyword.
May 12, 2013 at 4:54 pm |
I leave a response whenever I appreciate a post on a site or I have something to valuable to contribute to the discussion.
Usually it’s triggered by the fire displayed in the article I read. And on this post Internal And Protected | Andrew Smith. I was excited enough to leave a thought 😉 I do have a few questions for you if you don’t mind.
Could it be simply me or do a few of the remarks appear as if they are
written by brain dead folks? 😛 And, if you are writing at
other online social sites, I’d like to follow everything new you have to post. Would you list all of your community sites like your Facebook page, twitter feed, or linkedin profile?
May 13, 2013 at 5:35 am |
Je m’appelle Fabienne.
Je suis une fille de quarante-huit printemps !
Ce que je fais : barmaid . Mes amis disent régulièrement que je suis taciturne.
May 21, 2013 at 8:04 am |
Je suis une jeune de 44 ans .
Je porte le joli nom de Eleanor.
je suis des études de conductrice de ligne de fabrication .
On dit de moi que je suis cool.
May 21, 2013 at 8:08 pm |
bonjour Je m’appelle Fifine.
Je suis vieille de quarante-trois ans .
Je voudrais devenir scripte . Mon naturel est plutôt timide.
May 21, 2013 at 8:46 pm |
Really no matter if someone doesn’t be aware of afterward its up to other viewers that they will assist, so here it happens.
May 22, 2013 at 9:34 pm |
salut,hello,ça roule ? Mon nom est Susanne.
Je suis une femme de quarante-quatre printemps .
Ce que je fais dans la vie, étudiante ! Si je suis parfois revêche, ce n’est pas forcément un défaut ?
May 30, 2013 at 1:50 am |
Je m’appelle Cosette.
Je suis agée de quarante-quatre années !
Je suis agent de propreté urbaine . Il est dit parfois de moi que je suis drôle.
June 1, 2013 at 7:45 pm |
Je suis une jeune fille de 44 berges !
Je porte le joli nom de Anne.
Mon boulot, assistante maternelle ! Si je suis parfois
joyeuse, ce n’est pas forcément un défaut ?
June 2, 2013 at 12:49 pm |
hello, Je m’appelle Colette.
Je suis agée de 30 années .
J’ai repris mes études pour devenir éleveuse ! Mon caractère est plutôt réservé.
June 3, 2013 at 7:38 am |
Je suis une jeune fille de quarante-huit piges .
Parnella à votre service
Mon travail est fleuriste … Est-ce un défaut d’être attentionnée ?
June 4, 2013 at 4:24 pm |
We are a group of volunteers and starting a new
scheme in our community. Your website offered us with valuable information to work on.
You’ve done a formidable job and our entire community will be thankful to you.
June 5, 2013 at 11:18 am |
Hello; Je m’appelle Slainie.
Je suis agée de quarante-six ans .
Je suis graphiste . Mes amies racontent régulièrement que je suis pète sec.
June 6, 2013 at 3:10 am |
bonjour Je suis agée de trente-huit années ; je n’ai pas de problème là dessus .
je suis Noémi
je fais un stage de ingénieur chimiste . Mes amis disent que je suis un drole d’oiseau.
June 12, 2013 at 10:40 pm |
Good post. I learn something new and challenging on sites I
stumbleupon every day. It will always be useful to read through content from other writers and practice a little something from their sites.
June 17, 2013 at 10:46 am |
Ici Gabrielle
J’ai trente-cinqA .
je suis en ce moment des études de hôtesse de l’air .
Mon caractère est plutôt timide.
June 17, 2013 at 10:52 am |
salut, J’ai trente-septA ; je n’ai pas de problème là dessus
.
Je me nomme Thérèse.
je fais un stage de caviste . Il est dit de moi que je parais drôle.
June 19, 2013 at 8:11 pm |
hey ! je suis Yolette
Je suis agée de 41 ans !
je fais un stage pour devenir technicienne de labo .
Est-ce un défaut que d’être enjouée ?
June 24, 2013 at 2:49 am |
bonjour à tous, je suis Avelaine
Je suis agée de 40 années .
je suis actuellement des études de enseignante .
Si je suis parfois réservée, ce n’est pas forcément un défaut ?
June 27, 2013 at 7:20 am |
Je viens de fêter mon 27ième anniversaire. !
je suis Nicolette
Mon boulot: urbaniste … il semble que je suis une vraie pomme.
June 27, 2013 at 10:24 pm |
J’ai 41A !
je suis Jacqueline
J’ai repris mes études pour etre opératrice de fabrication !
Je suis plutôt d’un naturel timide.
June 29, 2013 at 3:07 am |
Je suis vieille de trente-neuf printemps ,
et j’assume totalement .
Je me nomme Ermengardi.
Mon travail est enquêtrice . Mes amis racontent que je suis rigolote.
June 30, 2013 at 5:45 pm |
bonjour Mon nom est Clementine.
Je viens de fêter mon 34ième anniversaire. !
J’ai repris mes études pour devenir prof de lycée . Est-ce un défaut que d’être enjouée ?
July 4, 2013 at 1:11 pm |
Mon nom est Luce.
Je suis vieille de trente-six piges : je n’ai pas de complexe à le dire !
je suis en ce moment des études de guide interprète . Je suis plutôt d’un caractère souriant.
July 7, 2013 at 4:37 pm |
Romaine à votre service
Je souffle mes trente-neuf bougies dans un mois .
je fais un stage de cartographe . Est-ce un défaut que d’être cool ?
July 11, 2013 at 3:11 am |
comment va ? Je suis vieille de quarante-trois berges !
Capucine à votre service
Ce que je fais : vendeuse en grande surface ! Est-ce
un défaut d’être attentionnée ?
July 11, 2013 at 8:18 am |
J’ai 35A .
Je porte le joli nom de Marjolaine.
Mon occupation principale, prof de musique . il apparaît que je suis une bonne poire.
July 11, 2013 at 10:37 am |
Je suis une jeune femme de 21 berges j’assume totalement mon age .
Je me nomme Heloise.
Mon métier, aide comptable . On dit régulièrement de moi que je suis pète sec.
January 28, 2014 at 10:39 am |
Hello everybody, here every person is sharing these knowledge, so it’s good to
read this weblog, and I used to pay a visit this weblog everyday.
April 13, 2014 at 7:11 pm |
This is the right website for anybody who hopes to understand this topic.
You know a whole lot its almost tough to argue with you (not that I really will
need to…HaHa). You definitely put a brand new spin on a
subject which has been discussed for decades. Excellent stuff, just
wonderful!
April 13, 2014 at 7:40 pm |
Thanks for sharing such a fastidious opinion, article is pleasant, thats why i have
read it entirely
May 19, 2014 at 3:42 pm |
Hello Je tenais juste à vous remercier pour ce très bon article.
J’était justement à la recherche d’information à cee sujet dephis un un certtains temps et j’ai
trouvé enfin de plus ample info sur le sujet.
Et par dessus tout, je voulais aussi vous remercier pour votre expertise, lles informations que vous avances sont simplement très intéressant.
Bon travail et à bientôt
September 23, 2014 at 5:41 am |
I rarely comment, but i did a few searching and wound up here Internal And Protected | Andrew Smith.
And I do have 2 questons for you iif you don’t mind.
Could it be just me or does it appear like some
of thhe remarks appear like they are left by brain dead visitors?
😛 And, if you are writing at additional sites, I’d like to follow everything fresh you have to post.
Could you make a list of all of your communal pages like your linkedin profile, Facebook page or twitter feed?
September 27, 2015 at 1:21 am |
hi!,I really like your writing very so much! share we communicate extra approximately your post on AOL?
I require an expert in this space to unravel my problem.
May be that’s you! Looking ahead to see you.