473,394 Members | 1,696 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Oddity with 'protected internal' and derivation

I am refactoring some code to move some base classes into a separate
assembly. One of these base classes has a member property which is
'protected internal'. However when I move these base classes to another
assembly, the compiler complains that the override in the derived class,
also declared as 'protected internal', is trying to change the access
modified from 'protected', which is clearly not the case. (I have checked
the metadata in the assembly and the base class property is 'famorassem'.)
If I change the derived class declaration to just 'protected', it works OK.
Anybody have an explanation as to why it is working this way?
Apr 26 '07 #1
13 2796
The compiler message is unclear but I think you're getting an error
because you have a visibility conflict.

When you have "protected internal" method F in class C1 which resides
in assembly A1, F is visible to C1-derived classes anywhere, plus to
all classes in A1.

Now when you put a derived class C2 in assembly A2 that overrides F
with the same protected internal modifier, the override is still
visible to derived classes anywhere -- but it's also visible
throughout A2 (but not A1) whereas the original method is visible
throughout A1 (but not A2).

Now if some non-C2 method in A2 has a C1 object and tries to call F,
just what method should it get? It can't get C1.F because that's
internal to A1, and it can't get C2.F because that's protected to C2.
Same for a non-C1 method in A1 that has a C2 object.

In my opinion, protected internal should not be used except with
internal classes. It's asking for trouble to expose a class with
protected internal methods to other assemblies.
--
http://www.kynosarges.de
Apr 26 '07 #2

"Chris Nahr" <di******@kynosarges.dewrote in message
news:hb********************************@4ax.com...
and it can't get C2.F because that's protected to C2.
Well that's what the compiler is doing, the question is why it is doing it.
If the framework allowed for the override to be also 'protected internal'
then it *could* get C2.F. The question is, what evil is the framework
preventing by insisting on changing the access to 'protected' in the derived
class. This I cannot understand.
Same for a non-C1 method in A1 that has a C2 object.
Which would mean a circular reference of assemblies.
In my opinion, protected internal should not be used except with
internal classes. It's asking for trouble to expose a class with
protected internal methods to other assemblies.
Agreed - I wouldn't have designed it that way myself, I'm refactoring
someone else's code. It's just a real PITA that the compiler is behaving
this way because it means that I also have to refactor the several dozen
classes derived from this base class as a result of moving the base class
into a different assembly.
Apr 26 '07 #3
Hello,
Well that's what the compiler is doing, the question is why it is
doing it. If the framework allowed for the override to be also
'protected internal' then it *could* get C2.F. The question is, what
evil is the framework preventing by insisting on changing the access
to 'protected' in the derived class. This I cannot understand.
It prevents you from “broadening” the visibility. That method used to be
visible to any types in the A1 assembly. If you override it as “protected
internal”, you'll make it visible to the A2 assembly too, which is not consistent.
“protected internal” (“[visible to] family or assembly” in .NET) is actually
“protected or internal”. You cannot override “internal” members in another
assembly, but you can override “protected”. When you override a “protected
internal” member, its “internal” part of the existence is “left behind in
the base class in the A1 assembly”, just the “protected” part is left for
you to override.
Which would mean a circular reference of assemblies.
Which is just OK with .NET, why not?
Agreed - I wouldn't have designed it that way myself, I'm refactoring someone
else's code. It's just a real PITA that the compiler is behaving this way
because it means that I also have to refactor the several dozen classes derived
from this base class as a result of moving the base class into a different
assembly.

A refactoring tool could have handled that for you, but of course I cannot
be sure as I don't know your class hierarchy.
(H) Serge
Apr 26 '07 #4
On Thu, 26 Apr 2007 11:00:03 +0100, "Clive Dixon" <clived at digita
dot comwrote:
>Well that's what the compiler is doing, the question is why it is doing it.
If the framework allowed for the override to be also 'protected internal'
then it *could* get C2.F.
No, it couldn't because it's using a C1 reference! C1 is defined in
A1, so the protected internal modifier that the compiler sees is
relative to A1, not to A2, so it's not possible to reach C2.F with
such a reference.

Code calling F from within A2 but outside C2 would succeed if F was
called on a C2 reference but fail if called on a C1 reference -- even
if both underlying objects were actually of type C2. That would break
a basic assurance of polymorphism. The compiler must prevent that.
--
http://www.kynosarges.de
Apr 26 '07 #5
<"Clive Dixon" <clived at digita dot com>wrote:
I am refactoring some code to move some base classes into a separate
assembly. One of these base classes has a member property which is
'protected internal'. However when I move these base classes to another
assembly, the compiler complains that the override in the derived class,
also declared as 'protected internal', is trying to change the access
modified from 'protected', which is clearly not the case. (I have checked
the metadata in the assembly and the base class property is 'famorassem'.)
If I change the derived class declaration to just 'protected', it works OK.
Anybody have an explanation as to why it is working this way?
I agree with everyone else's analysis, but it's interesting - the C#
spec doesn't mention this case as far as I can see. It says that it's
an error for the declared accessibility to be different, which is
ambiguous in terms of whether it means the modifiers specified of the
*effective* accessibility.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 26 '07 #6
Serge Baltic <ba*****@hypersw.netwrote:
Which would mean a circular reference of assemblies.

Which is just OK with .NET, why not?
I don't believe so - as far as I'm aware, if assembly A references
assembly B, the reverse can't be true.

For one thing, you've got a problem as to which you compile first...

You can have circular *class* references, but they need to be in the
same assembly.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 26 '07 #7
Chris Nahr wrote:
The compiler message is unclear but I think you're getting an error
because you have a visibility conflict.

When you have "protected internal" method F in class C1 which resides
in assembly A1, F is visible to C1-derived classes anywhere, plus to
all classes in A1.
Let's point out that 'protected' is almost identical in meaning to
'public' - derived types can make it arbitrarily available, so it
doesn't give any strong guarantees, e.g. relating to invariants etc. For
invariance purposes, 'protected' needs to be treated as 'public'.
Now when you put a derived class C2 in assembly A2 that overrides F
with the same protected internal modifier, the override is still
visible to derived classes anywhere -- but it's also visible
throughout A2 (but not A1) whereas the original method is visible
throughout A1 (but not A2).

Now if some non-C2 method in A2 has a C1 object and tries to call F,
just what method should it get? It can't get C1.F because that's
internal to A1, and it can't get C2.F because that's protected to C2.
Same for a non-C1 method in A1 that has a C2 object.
I don't see how this is relevant. Accessing protected member F on an
expression of type C1 in assembly A2 won't work - but that has nothing
to do with the existence or non-existence of C2 and its hypothetical
protected internal override of C1.F.

A protected internal override of C1.F called C2.F gives permission to
call C2.F inside A2 on expressions of type C2 and descendants of C2. But
that's orthogonal to whether or not C1.F is declared protected or
protected internal.

In my opinion, it's a slight flaw of C# that it doesn't permit
increasing visibility in overrides.
In my opinion, protected internal should not be used except with
internal classes. It's asking for trouble to expose a class with
protected internal methods to other assemblies.
I don't agree - exposing a class with protected internal methods to
other assemblies is identical in effect (to the other assemblies) as
exposing a class with merely protected methods. And I can't imagine that
you mean to prohibit all protected methods!

-- Barry

--
http://barrkel.blogspot.com/
Apr 26 '07 #8
Barry Kelly <ba***********@gmail.comwrote:
When you have "protected internal" method F in class C1 which resides
in assembly A1, F is visible to C1-derived classes anywhere, plus to
all classes in A1.

Let's point out that 'protected' is almost identical in meaning to
'public' - derived types can make it arbitrarily available, so it
doesn't give any strong guarantees, e.g. relating to invariants etc. For
invariance purposes, 'protected' needs to be treated as 'public'.
Unless the class is internal, of course, and therefore can't be derived
from in other assemblies. If you "own" the only assembly that can
contain classes that can derive from the class in question, there are
more guarantees.

Likewise, if you only have private constructors, you can guarantee that
only nested classes within the class can derive from the class - again
making protected more useful.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 26 '07 #9
Jon Skeet wrote:
Barry Kelly <ba***********@gmail.comwrote:
When you have "protected internal" method F in class C1 which resides
in assembly A1, F is visible to C1-derived classes anywhere, plus to
all classes in A1.
Let's point out that 'protected' is almost identical in meaning to
'public' - derived types can make it arbitrarily available, so it
doesn't give any strong guarantees, e.g. relating to invariants etc. For
invariance purposes, 'protected' needs to be treated as 'public'.

Unless the class is internal, of course, and therefore can't be derived
from in other assemblies. If you "own" the only assembly that can
contain classes that can derive from the class in question, there are
more guarantees.

Likewise, if you only have private constructors, you can guarantee that
only nested classes within the class can derive from the class - again
making protected more useful.
I agree, I considered including a paragraph on these exceptions, but I
thought it would be too pick-nickety. :)

-- Barry

--
http://barrkel.blogspot.com/
Apr 26 '07 #10
Hello,
>>Which would mean a circular reference of assemblies.
Which is just OK with .NET, why not?
I don't believe so - as far as I'm aware, if assembly A references
assembly B, the reverse can't be true.
Easily. I've just written a couple such assemblies:

w:\Circular>a1.exe
Created
I'm A1.C1, A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null. I have
a field A2.C2.
I'm A2.C2, A2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null. I have
a field A1.C1.
Done

You don't have to take my word for it, you can just check the references
list of System.dll and System.Xml.dll :) Surprisingly, they're circularly-referenced
as well.
For one thing, you've got a problem as to which you compile first...
To reference an assembly at compile-time, all you need is the assembly name,
version, culture, and public key token. All of them are known even before
the assembly is compiled.
You can have circular *class* references, but they need to be in the
same assembly.
No, they needn't. Those C1 and C2 classes of mine each have a field of the
other's type. That compiles, passes peverify.exe, loads, and runs.

It's true that you cannot do circular references in C#, which is mostly because
C# wants to validate everything at compile time, and you cannot verify much
until all the referenced assemblies exist. So it's a bit offtopic in a .csharp
newsgroup, but still possible in the real world ;)

(H) Serge
Apr 26 '07 #11
(I started replying before reading the whole thing - I've left my
comments in rather than taking them all out, in order to explain my
reactions.)

Serge Baltic <ba*****@hypersw.netwrote:
>Which would mean a circular reference of assemblies.
Which is just OK with .NET, why not?
I don't believe so - as far as I'm aware, if assembly A references
assembly B, the reverse can't be true.

Easily. I've just written a couple such assemblies:

w:\Circular>a1.exe
Created
I'm A1.C1, A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null. I have
a field A2.C2.
I'm A2.C2, A2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null. I have
a field A1.C1.
Done
How did you compile those then?
You don't have to take my word for it, you can just check the references
list of System.dll and System.Xml.dll :) Surprisingly, they're circularly-referenced
as well.
Indeed, you're right. I'm frankly confused.
For one thing, you've got a problem as to which you compile first...

To reference an assembly at compile-time, all you need is the assembly name,
version, culture, and public key token. All of them are known even before
the assembly is compiled.
But if you add a reference to an assembly, it will check whether or not
that exists, won't it? Otherwise how can it ensure that the type you're
referencing exists?
You can have circular *class* references, but they need to be in the
same assembly.

No, they needn't. Those C1 and C2 classes of mine each have a field of the
other's type. That compiles, passes peverify.exe, loads, and runs.

It's true that you cannot do circular references in C#, which is
mostly because C# wants to validate everything at compile time, and
you cannot verify much until all the referenced assemblies exist. So
it's a bit offtopic in a .csharp newsgroup, but still possible in the
real world ;)
Ah, I see. It all makes sense now - you're not using the C# compiler.
That certainly changes things. Your comment of "Which is just OK with
..NET, why not?" (referring to circular assembly references) implies
that there's no problem with circular references. Not being able to
compile such a situation in C# is certainly a problem for most of us :)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 27 '07 #12
Hello,
Ah, I see. It all makes sense now - you're not using the C# compiler.
That certainly changes things. Your comment of "Which is just OK with
.NET, why not?" (referring to circular assembly references) implies
that there's no problem with circular references. Not being able to
compile such a situation in C# is certainly a problem for most of us
:)
Uh … well … I'm sorry, but of course you can write them in C# :) I've rewritten
my example in .cs, and here're two valid circularly-referencing C#-compiled
assemblies:

w:\Circular\01>a1.exe
I'm "A1.C1, A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". I
can see "A2.C2, A2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null".
I'm "A2.C2, A2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". I
can see "A1.C1, A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null".

Using just two .cs files and a few csc.exe calls to compile them. Easy fun.
:)

(H) Serge
Apr 27 '07 #13
Serge Baltic <ba*****@hypersw.netwrote:
Ah, I see. It all makes sense now - you're not using the C# compiler.
That certainly changes things. Your comment of "Which is just OK with
.NET, why not?" (referring to circular assembly references) implies
that there's no problem with circular references. Not being able to
compile such a situation in C# is certainly a problem for most of us
:)

Uh ? well ? I'm sorry, but of course you can write them in C# :) I've rewritten
my example in .cs, and here're two valid circularly-referencing C#-compiled
assemblies:

w:\Circular\01>a1.exe
I'm "A1.C1, A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". I
can see "A2.C2, A2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null".
I'm "A2.C2, A2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". I
can see "A1.C1, A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null".

Using just two .cs files and a few csc.exe calls to compile them. Easy fun.
:)
So how did you compile them? I can see how you could compile one
version of assembly A which *didn't* refer to B, then compile B
referring to A, then recompile A referring to B. Hardly the kind of
thing you'd want to do on a regular basis though, is it? In particular,
I suspect you wouldn't be able to do it within Visual Studio, although
admittedly I haven't tried.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Apr 27 '07 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Andy Ward | last post by:
Given the following code: class A { protected: int pro; }; class B : public A { public:
28
by: Act | last post by:
Why is it suggested to not define data members as "protected"? Thanks for help!
12
by: xxx | last post by:
I'm having a little trouble understanding why a derivative class cannot access a protected member of the base class in the following code: #include <stdio.h> class CBase { protected: int...
8
by: Carlos J. Quintero | last post by:
Hi, As you know the current keywords "protected internal" (C#) or "Protected Friend" (VB.Net) means "Protected Or internal" (C#) or "Protected Or Friend" (VB.Net), that is, the member is...
6
by: Sgt. Sausage | last post by:
I know it's not possible, but I need a protected internal interface: protected internal interface ISomeInterface{ // yadda yadda yadda } Basically, I need an interface that is completely...
2
by: Kolozs, Áron | last post by:
Hi everybody, The C# compiler reports a Compiler Error CS0052 in the following situation: I declared a type marked as "internal": namespace MyNamespace { internal class MyInteralClass
4
by: newbie120 | last post by:
Hi all maybe its just been a long day, but i have a question about call access modifiers in C#. Consider the following code. namespace Application { private class Class1 { int i;
16
by: Fir5tSight | last post by:
Hi All, I have a small C#.NET program that is as follows: using System; class A { protected int x = 123; }
2
by: jehugaleahsa | last post by:
Hello: I have a public abstract class. The concrete subclasses must pass an instance of an internal class to the abstract class' ctor. I like to make the constructors of my abstract classes...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.