English 中文(简体)
C# set accessor accessible to all types in assembly, and get assessor only to derivated types. How to?
原标题:

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).

最佳回答

(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;
}
问题回答

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; }
}




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签