Trouble with internal classes (error CS0051: Inconsistentaccessibility)

D

dylan.miller

I'm having trouble understanding the internal access modifier. There
are many classes in my assembly that should not be accessible outside
of the assembly. I've used the internal access modifier for these
classes. I have public classes that use the internal classes, but I
get a CS0051 error if I use an internal class as a parameter to a
protected function of a public class. For example:

internal class InternalClass
{
}

public class PublicClass
{
protected void ProtectedFunction(InternalClass internalClass)
{
}
}

When I compile the code above, I get the following error:
error CS0051: Inconsistent accessibility: parameter type
'InternalClass' is less accessible than method
'PublicClass.ProtectedFunction(InternalClass)'

It seems like I should be able to do this, since a protected function
is hidden from the user of a class, and it seems like "hidden" code
should be able to use internal classes. I assume the error occurs
because a class could be derived from PublicClass outside of the
assembly, but I don't plan to do that. I thought the "protected
internal" access modifier might be the solution, but it means
protected OR internal, where what I want is protected AND internal.

Possible solutions:
1) Change ProtectedFunction() from protected to internal. This is not
good, because then ProtectedFunction() becomes accessible to any code
in the assembly. I want ProtectedFunction() hidden.
2) Change InternalClass from internal to public. This is not good,
because a domino effect will occur and I'll end up having to change
most of my internal classes to public to avoid the CS0051 error.

Is there a solution I'm missing, or is this just a limitation of
internal classes?
 
R

Rudy Velthuis

internal class InternalClass
{
}

public class PublicClass
{
protected void ProtectedFunction(InternalClass internalClass)
{
}
}

When I compile the code above, I get the following error:
error CS0051: Inconsistent accessibility: parameter type
'InternalClass' is less accessible than method
'PublicClass.ProtectedFunction(InternalClass)'

Problem is that a protected member is also accessible from outside the
assembly, by derived classes (that is exactly why there are protected
methods: so you can call them, but ONLY in derived classes). These
derived classes are often not in the same assembly. But as the type of
the parameter internalClass is not visible from outside, there would be
no way for an external class to use such a protected method.

So the compiler rightly claims that the visibility of the internalClass
parameter is too low to be used in a protected method.
--
Rudy Velthuis http://rvelthuis.de

"Anyone who considers arithmetical methods of producing random
digits is, of course, in a state of sin."
-- John von Neumann (1903-1957)
 
J

Jeroen Mostert

I'm having trouble understanding the internal access modifier. There
are many classes in my assembly that should not be accessible outside
of the assembly. I've used the internal access modifier for these
classes. I have public classes that use the internal classes, but I
get a CS0051 error if I use an internal class as a parameter to a
protected function of a public class. For example:
Obviously. :)
internal class InternalClass
{
}

public class PublicClass
{
protected void ProtectedFunction(InternalClass internalClass)
{
}
}

When I compile the code above, I get the following error:
error CS0051: Inconsistent accessibility: parameter type
'InternalClass' is less accessible than method
'PublicClass.ProtectedFunction(InternalClass)'

It seems like I should be able to do this, since a protected function
is hidden from the user of a class,

But not from clients that derive from this class. They could see
ProtectedFunction() but be unable to call it because InternalClass isn't
accessible. This situation makes no sense, so the compiler rightfully complains.
and it seems like "hidden" code should be able to use internal classes. I
assume the error occurs because a class could be derived from PublicClass
outside of the assembly, but I don't plan to do that.

It doesn't really matter what you plan on doing, but what can actually be
done. As it stands a class external to the assembly could inherit from this
class, creating the problem mentioned above.
I thought the "protected internal" access modifier might be the solution,
but it means protected OR internal, where what I want is protected AND
internal.
C# has no support for this, and this is arguably not a bad thing, because
that would effectively create a rather dubious discrepancy between
inheriting from within the assembly and inheriting from without it. Such
scenarios are typically better solved with encapsulation rather than
inheritance.
Possible solutions:
1) Change ProtectedFunction() from protected to internal. This is not
good, because then ProtectedFunction() becomes accessible to any code
in the assembly. I want ProtectedFunction() hidden.
2) Change InternalClass from internal to public. This is not good,
because a domino effect will occur and I'll end up having to change
most of my internal classes to public to avoid the CS0051 error.

Is there a solution I'm missing, or is this just a limitation of
internal classes?

Probably both. Without knowing your scenario it's hard to tell what approach
would be best. Marking the method "internal" seems actually fairly
uncontroversial to me -- yes, this means the method isn't hidden, but so
what? You're relying on the kindness of close strangers to keep the use of
internal types to a proper level anyway. The accessibility modifiers simply
aren't flexible enough to express every reasonable scenario, but this is a
trade-off between flexibility and ease of use.

You're probably best off rethinking the way you've structured your classes.
You may be able to split off the parts that need InternalClass so they won't
need to be exposed to outside clients. Creative use of inner classes and
encapsulation may also be of help, but this can quickly snowball into a
design that technically does what you want in terms of visibility but is
highly unintuitive.
 
D

dylan.miller

I understand that, but I'm not planning on deriving classes from
PublicClass outside of the assembly (The sealed keyword has no effect
on the error, by the way). I was just hoping to expose a very small
set of public classes that could be used as an API, and hide the inner
workings of the API from the user. If I have to change many of the
internal classes to public to avoid the CS0051 error, it's not as
elegant, since such classes are not meant to be used outside of the
assembly.

I guess this is a feature of C# that I'm still wrapping my head
around. Internal classes just don't seem as useful with this
limitation.
 
D

dylan.miller

Thanks Jeroen and Rudy. I understand things much better now, and I
guess there isn't any way around this other than restructuring the
code. I can think of some convoluted ways to keep my minimal set of
public classes (API) as well as keep functions protected rather than
internal, but it's hard to justify making the code more complex when
simply changing the access modifiers makes the problems go away, so
I'll probably end up going with the #1 or #2 solution in my original
post.
 
R

Rudy Velthuis

I understand that, but I'm not planning on deriving classes from
PublicClass outside of the assembly (The sealed keyword has no effect
on the error, by the way).

Hmmm... I guess that the compiler has that as a general rule, and
simply disregards the sealed keyword in this respect.
--
Rudy Velthuis http://rvelthuis.de

"Ask her to wait a moment - I am almost done."
-- Carl Friedrich Gauss (1777-1855), while working, when
informed that his wife is dying
 
J

Jeroen Mostert

Rudy said:
Hmmm... I guess that the compiler has that as a general rule, and
simply disregards the sealed keyword in this respect.

There's not much point to declaring the class sealed anyway, because then
there's no way of using the protected method outside the class. The compiler
will issue a warning that says as much. You may as well declare the method
private in that case, and then the error of course disappears.
 
L

Lasse Vågsæther Karlsen

I understand that, but I'm not planning on deriving classes from
PublicClass outside of the assembly (The sealed keyword has no effect
on the error, by the way). I was just hoping to expose a very small
set of public classes that could be used as an API, and hide the inner
workings of the API from the user. If I have to change many of the
internal classes to public to avoid the CS0051 error, it's not as
elegant, since such classes are not meant to be used outside of the
assembly.

I guess this is a feature of C# that I'm still wrapping my head
around. Internal classes just don't seem as useful with this
limitation.

What about protected internal?
If you don't intend the method to be available outside the assembly
anyway, internal might work.
 
D

dylan.miller

What about protected internal?
If you don't intend the method to be available outside the assembly
anyway, internal might work.

When you mark a function protected internal, it's visible to all code
inside the assembly as if it were public (not good), and it's also
visible outside the assembly as a protected function, so I'd still get
the error.
 
R

Rudy Velthuis

Jeroen said:
There's not much point to declaring the class sealed anyway, because
then there's no way of using the protected method outside the class.

Correct. Then it can just as well be pivate.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top