C # устанавливает аксессор доступным для всех типов в сборке и получает оценку только для производных типов Как? - PullRequest
4 голосов
/ 17 января 2010

Это свойство в типе с нет доступа модификатор (таким образом internal доступ):

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

позволяет всем типам в сборке SomeType использовать get и set средства доступа. Проблема : как ограничить доступ к set только только типам, производным от SomeType (и действительно SomeType)?

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

отклоняется компилятором, потому что protected считается менее строгим, чем internal (предположительно: protected имеет пересечение с internal, но не полностью в internal -> Производные типы могут существовать за пределами internal).

Какой будет код для доступа к любому типу в сборке и установки только для производных типов в сборке?

Редактировать : после просмотра ответов я думаю, что мне нужно добавить еще одну характеристику свойства, поскольку это может иметь значение в решении: тип свойства на самом деле SomeType. Отредактированный код:

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

Если свойство объявлено public, то компилятор выдает ошибку (тип свойства SomeType менее доступен для свойства Length).

Ответы [ 3 ]

5 голосов
/ 17 января 2010

(РЕДАКТИРОВАТЬ: я только что проверил, и это работает, даже когда тип свойства совпадает с объявленным типом. Однако, не работает, когда вы пытаетесь объявить свойство в типе public , где типом свойства является внутренний тип.)

Вы не можете сделать это в C # (строго говоря), но вы можете сделать что-то очень похожее:

protected internal int Length { get; protected set; }

(Это используется автоматически реализованным свойством только для простоты; тот же метод будет работать и для «нормального» свойства.)

Это сделает «геттер» доступным для любого типа в пределах одной и той же сборки и производных типов; «Сеттер» будет доступен только для производных типов. Так как ваш класс в любом случае является внутренним, это все равно в значительной степени эквивалентно - теоретически, метод получения будет доступен для типов вне сборки, но, поскольку класс является внутренним, ничто из другой сборки не должно быть производным от вашего типа.

Проблема в том, что свойства требуют, чтобы один уровень доступа был «подмножеством» другого; internal и protected не работают так - один тип может быть в одной сборке, но не может быть получен из рассматриваемого типа; из него может быть получен другой тип, но в другой сборке. В основном они ортогональны.

Приведенное выше решение работает, потому что protected internal означает, что оно доступно для любого типа, который или в той же сборке или , полученного из типа. Очевидно, что каждый из protected и internal в отдельности является подмножеством этого.

Вы могли бы создать свойство internal, которое было бы дополнительно ограничено для установщика, если бы C # имел некоторый эквивалент уровня доступа CLR "семейство и сборка". (protected internal эквивалентно «семейству или сборки».) К сожалению, для вас это не так: (

Если вы действительно хотите первоначально заявленные цели (например, если у вас позже есть публичный класс, к которому вы хотите применить те же ограничения), вам придется сделать хотя бы один из них отдельным методом вместо этого, например

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

protected void SetLength(int value)
{
    this.length = value;
}
3 голосов
/ 17 января 2010

Поскольку сам класс виден только в декларируемой сборке (из-за неявного модификатора доступа internal), просто установите метод get для свойства public и метод установки protected:

class SomeType {
    private int length;

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

Получатель не будет недоступен вне вашей сборки, так как сам класс не виден.


Не по теме: если у вас недавно установлен компилятор C #, вы можете использовать вместо него автоматические свойства:

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

Это только трюк с языком / компилятором, поэтому вам не нужно компилировать его с использованием фреймворка версии 3.X, чтобы использовать его.

0 голосов
/ 17 января 2010

Не можете ли вы перевернуть (не проверял):

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