Question

This property in a type with no access modifier (thus internal access):

class SomeType {
    private int length;
    internal int Length {
        get { return length; }
        set length = value; }
    }
}

allows all types within the assembly of SomeType to use get and set accessors. Problem: how to restrict the access to set to only types derived from SomeType (and SomeType indeed)?

internal int Length {
    get { return length; }
    protected set length = value; }
}

is rejected by the compiler, because protected is said to be less restrictive than internal (supposedly: protected has an intersection with internal, but is not entirely included in internal --> Derived types can exist beyond the scope of internal).

What would be the code to have get accessed by any type within the assembly, and set only by derivated types within the assembly?

Edit: after reviewing the answers, I think I need to add another characteristic of the property, since it may make a difference in the solution: the type of the property is actually SomeType. The edited code is:

class SomeType {
    private SomeType length;
    internal SomeType Length {
        get { return length; }
        set length = value; }
    }
}

If the property is declared public, then the compiler issues an error (the property type SomeType is less accessible the property Length).

Was it helpful?

Solution

(EDIT: I've just checked, and this works even when the type of the property is the same as the declaring type. However, it doesn't work when you're trying to declare a property within a public type where the type of the property is an internal type.)

You can't quite do that in C# (strictly speaking), but you can do something very similar:

protected internal int Length { get; protected set; }

(This is using an automatically implemented property just for simplicity; the same technique would work for a "normal" property too.)

This will make the "getter" accessible to any type within the same assembly and derived types; the "setter" will only be accessible to derived types. As your class is internal anyway, this is pretty much equivalent anyway - the getter would theoretically be accessible to types outside the assembly, but as the class is internal, nothing from a different assembly should be deriving from your type anyway.

The problem is that properties require that one access level is a "subset" of the other; internal and protected don't work like that - one type can be in the same assembly but not derived from the type in question; another type can be derived from it but in a different assembly. They're orthogonal, basically.

The above solution works because protected internal means it's accessible to any type which is either in the same assembly or derived from the type. Clearly each of protected and internal individually is a subset of this.

You would be able to make an internal property which was further restricted for the setter if C# had some equivalent to the CLR "family and assembly" access level. (protected internal is equivalent to "family or assembly".) Unfortunately for you, it doesn't :(

If you really want the originally stated goals (e.g. if you later have a public class you want to apply the same restrictions to), you'll have to make at least one of them a separate method instead, e.g.

private int length;
internal int Length { get { return length; } }

protected void SetLength(int value)
{
    this.length = value;
}

OTHER TIPS

Since the class itself is only visible in the declaring assembly (due to the implicit internal access modifier), just make the getter on the property public and the setter protected:

class SomeType {
    private int length;

    public int Length {
        get { return length; }
        protected set { length = value; }
    }
}

The getter will not be accessible out outside of your assembly, since the class itself is not visible.


Off topic: if you have a recent C# compiler, you might want to use auto properties instead:

class SomeType {
    public int Length { get; protected set; }
}

This is a language/compiler trick only, so you do not have to compile against a version 3.X framework to make use of it.

Can't you turn it around (haven't tested it):

protected int Length
{
    internal get { return length; }
    set { length = value; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top