views:

473

answers:

7

I was having the problem of wanting a property to have an internal getter and a protected setter, as described in this question, and I thought I solved that by doing the following:

public class Accessor : AccessorBase
{
    private Connection _connection;

    protected void setConnection(Connection value)
    {
        _connection = value;
    }

    internal Connection GetConnection()
    {
        return _connection;
    }
    ...
}

However, I'm now getting this error:

Inconsistent accessibility: parameter type 'Connection' is less accessible than method 'setConnection(Connection)'

This is because I have internal class Connection. I would rather not make Connection a public class, while Accessor needs to be public, so how can I get around this error while still maintaining an internal getter and a protected setter?

+1  A: 

If the class Connection is internal, a class deriving Accessor won't be able to call protected setConnection since it doesn't have access to Connection.

If setConnection is to be protected, Connection will have to be public.

Coincoin
Why not, if the class deriving from Accessor is in the same namespace/project as both Accessor and Connection?
Sarah Vessels
"protected internal" means "protected" or "internal", which means it's less restrictive than just "protected".
Pent Ploompuu
@Sarah: C# doesn't care about where you are currently deriving the class. All it's telling you is you are trying to have a protected function in a public class that uses an internal class. This is illegal since any class deriving from your public class won't necessarily have access to Connection.
Coincoin
That wouldn't work, making the setter as protected internal resolves nothing
AlbertEin
+1 to even out the downvote.
Stan R.
@Abel..**protected internal** means **protected** OR **internal**
Stan R.
deleting... you are right, sorry for the misinfo...
Abel
+5  A: 

Unfortunately C# doesn't support "internal and protected" access modifiers (only "internal or protected" is supported), which means any protected members are visible outside the assembly and can't use an internal type.
Using internal instead of protected would be the most logical solution.

And you could vote at Microsoft Connect so that it might be added to C# someday.

Pent Ploompuu
Hm, I might be able to get around it by making `Connection` public and just making all its instance methods and constructors `internal`...
Sarah Vessels
Yes, that might be an acceptable solution.
Pent Ploompuu
+1, thanks for clarifying that, Pent - I'd post this in the old misconceptions thread if it weren't already overfull. (I found this a bit comforting: http://haacked.com/archive/2007/10/29/what-does-protected-internal-mean.aspx, plus it has an interesting nugget pointing out that the CLR supports and-ing the two visibilities; C# just doesn't have the syntax.)
Jeff Sternal
@Abel, protected internal means "protected" *OR* "internal" not AND
Stan R.
Stan, you're correct, thanks for correcting me, I always forget this idiot part of the C# spec (and just saw that Eric Lippert shares my opinion... lol)
Abel
I started thinking about similar situations in my own code and came to the conclusion that I've usually just replaced `protected` with `internal`.
Pent Ploompuu
A: 

Sorry, If you need that exact setup, you'll need to make your Connection class public.

Arjan Einbu
A: 

Unfourtanly you cannot do that. Since the Connection is internal some class deriving from Accessor from another assembly would not be able to see Connection, even if you mark the setter as protected internal it would solve nothing.

Your only hope is to make the class Connection public.

AlbertEin
interfaces would be his other hope too..:)
Stan R.
@Stan: and by 'his' you mean 'her', right? ;)
Sarah Vessels
+3  A: 

Create a public interface IConnection that your internal Connection object implements. Have your GetConnection and SetConnection methods accept and return IConnection instead of Connection.

Basic SOLID principles win again.

Randolpho
+1 This was *exactly* what I was about writing (without the side kick)...
Abel
+1 awesome answer..made my smile
Stan R.
And what kind of methods/properties should `IConnection` require? Whatever public methods are in `Connection`?
Sarah Vessels
@Sarah Vessels: Yes, exactly. For more information on why interfaces and abstractions in general are better, see the SOLID link in my answer, particularly The Dependency Inversion Principle. SOLID principles are very good general guidelines to adopt.
Randolpho
@Randolpho, this is generally excellent advice, but I don't think Sarah wants `Connection` to be publicly callable. An `IConnection` interface would defeat that desire, unless it's just a marker interface.
Jeff Sternal
@Jeff Sternal: Hmm... you make a good point, but I think the problem is that `Connection` cannot be internal if it's settable from a protected method. Any child class of `Accessor` would have to have access to `Connection` in order to override `SetConnection`. If `IConnection` is public, the derived class could pass any implementation of `IConnection` it wished, allowing `Connection` to remain internal.
Randolpho
A: 

Coincoin is correct, Accessor is a public class anyone can derive from it, this means from a different assembly as well. That derived class now has protected method to which you need to pass an internal (from another assembly) class. This would never work.

You need to either make Accessor internal or Connection public, or better yet follow Randolphos answer

Here is a code example of the problem

Assembly 1

//this class is only visible in Assembly 1
internal class Connection
{

}
public class Accessor
{
   protected void SetConnection(Connection con) { }
}

Assembly 2 - has reference to Assembly 1

//possible because Accessor is public
DerivedAccessor : Accessor
{
   void SomeMethod()
    {
        this.SetConnection(????) // you can't pass Connection, its not visible to Assembly2 
    }
}
Stan R.
+2  A: 

...any protected members are visible outside the assembly and can't use an internal type.

-- Pent Ploompuu's answer

One way of getting around this is to make Connection public while making all its instance methods and constructors internal.

Sarah Vessels
+1 for an excellent workaround. In the .NET BCL you occasionally see classes without any methods: everything's private or internal.
Abel
just hit this wall. it's a catch 22... you either allow visibility of your internal classes [but otherwise empty to the external world] or allow other internal classes to set something only derived classes should... humnnnn...
Padu Merloti