Как я могу предоставить вложенным структурам доступ к полям их родительских классов, не делая эти поля общедоступными или внутренними?

#c# #access-modifiers

#c# #модификаторы доступа

Вопрос:

У меня есть double[,] поле в классе, и важно, чтобы прямой доступ к нему не передавался извне, поэтому я создал свойство чтения-записи для управления им и создал его private . У меня также есть вложенный struct в классе, который я хочу сохранить как тип значения. Сама структура имеет double[,] поле, которое, опять же, управляется соответствующим свойством чтения-записи. При определенных условиях, если свойству присвоено значение, которое недопустимо определенным образом, оно выдает пользовательское exception . Один из аргументов, который мне нужно передать в exception , основан на значении double[,] поля из родительского класса, но, похоже, я не могу получить к нему доступ изнутри структуры, не создавая его public или internal . Я пробовал оба protected и private , но ни то, ни другое не работает. Есть ли другой обходной путь?

 class myClass {
    protected double[,] classField;
    public double[,] classProperty {
        get { return (double[,])classField.Clone();
        set { /* code to validate the value and assign it */ }
    }
    private struct myStruct {
        private double[,] structField;
        public structProperty{ 
            get { return (double[,])structField.Clone(); }
            set {
                if (!validate(value)) 
                    throw new customException(classField.getLength(1));
                structField = (double[,])value.Clone();
            }
        }
        //other fields, constructors, and methods...
    }
    //other fields, constructors, and methods...
}
  

Я рассматривал возможность доступа к свойству вместо поля, но мне понадобилось бы значение свойства для конкретного экземпляра, который поддерживает рассматриваемый экземпляр struct. Может быть, есть что-то вроде this.parent (я пробовал это, и это не сработало, но, возможно, какой-то обходной путь, похожий по концепции)?

Комментарии:

1. могу ли я проверить: вы хотите получить доступ к MyClass.classField здесь из MyStruct?

2. да, это верно

Ответ №1:

Я предполагаю, что вы хотите myStruct поговорить с classField содержащим myClass экземпляром.

Если это так: тогда проблема не в доступности — у нее уже есть доступ; проблема в области. Что касается компилятора, вложенность здесь не связана с созданием экземпляра, поэтому проблема в том, что у myStruct нет конкретного экземпляра classProperty , с которым можно было бы поговорить. Вот почему ошибка:

Ошибка CS0120 Для нестатического поля, метода или свойства ‘MyClass.classField’ требуется ссылка на объект

вместо доступности:

Ошибка CS0122 ‘MyClass.classField’ недоступен из-за его уровня защиты

Фактически, classField может быть private с точки зрения доступности: вложенный тип может видеть private члены содержащего типа.

Что вам нужно, так это сделать что-то вроде:

 private struct myStruct
{
    private readonly myClass _obj;
    public myStruct(myClass obj) => _obj = obj;
    // ...
}
  

и затем вместо того, чтобы просто classField , вам нужно сказать ему, чтобы он поговорил с _obj.classField , чтобы сообщить ему экземпляр. Вам также потребуется сконструировать myStruct передачу в конкретном myClass , к которому она относится.

В принципе: this.parent концепция, которую вы упоминаете в вопросе, не является неявной — вам нужно реализовать ее самостоятельно.

Комментарии:

1. Это не компилируется, могут ли структуры иметь конструкторы?

2. @Jerry да, они могут; Я использую синтаксис C # 7.3 здесь — если вы используете более ранний компилятор: public myStruct(myClass obj) { _obj = obj; }

3. Я понимаю свою ошибку, он жаловался, что stuctField не был назначен, я работал с кодом OP. Спасибо, Марк

4. lol тот факт, что вы должны явно имитировать функциональность this.parent с параметрами, действительно неудобен, но это работает. Спасибо!

5. @TaraStahler суть в том, что C # не предполагает, что ваша структура должна каким-либо образом отслеживать экземпляр, «содержащий» — myStruct определяется исключительно написанным вами кодом — никаких скрытых автоматических дополнительных полей. Это a: означает, что вы полностью понимаете размер / область видимости типа, который вы создаете (что может быть важно), b: означает, что он волшебным образом не становится недоступным для размытия (что было бы сделано при наличии поля, являющегося ссылкой на некоторого родителя; blittable === T : unmanaged для этой цели), и c: не ограничивает ваше использование myStruct экземпляров отношением 1: 1 с myClass экземплярами