Каков наилучший способ доступа к полю в охватывающем классе из вложенного класса?

Скажем, если у меня есть раскрывающийся список в форме, и у меня есть еще один вложенный класс внутри этого класса. Как лучше всего получить доступ к этому раскрывающемуся списку из вложенного класса?


person Community    schedule 08.10.2008    source источник
comment
Пожалуйста, дополните. Примеры были бы очень кстати.   -  person Craig    schedule 09.10.2008
comment
Ученик, я добавил тег вложенных классов к вашему вопросу, так как есть вопрос Когда следует использовать вложенные классы с этим тегом, и имеет смысл сгруппировать эти два ближе, чем просто использовать тег C #!   -  person Ray Hayes    schedule 09.10.2008
comment
Перспектива сделать это (со стандартным синтаксисом) довольно интересна... вроде замыканий в поведении. Несомненно, такой функцией злоупотребляли бы до тех пор, пока она не стала бы анти-паттерном, если бы она существовала =(   -  person Sprague    schedule 08.07.2013


Ответы (9)


В отличие от Java, вложенный класс не является специальным «внутренним классом», поэтому вам нужно передать ссылку. У Рэймонда Чена есть пример, описывающий различия здесь: Вложенные классы C# похожи на вложенные классы C++, а не на внутреннюю часть Java. классы.

Вот пример, когда конструктору вложенного класса передается экземпляр внешнего класса для дальнейшего использования.

// C#
class OuterClass 
{
    string s;
    // ...
    class InnerClass 
    {
       OuterClass o_;
       public InnerClass(OuterClass o) { o_ = o; }
       public string GetOuterString() { return o_.s; }
    }
    void SomeFunction() {
        InnerClass i = new InnerClass(this);
        i.GetOuterString();
    }

}

Обратите внимание, что InnerClass может получить доступ к «s» OuterClass, я не модифицировал код Рэймонда (как я указал выше), поэтому помните, что «string s;» — это private, потому что не было указано другое разрешение на доступ.

person Ray Hayes    schedule 08.10.2008

Вложенные типы не похожи на внутренние классы в Java — в них нет неотъемлемого экземпляра содержащего типа. (Они больше похожи на статические вложенные классы в Java.) Фактически это отдельные классы с двумя отличиями:

  • Если содержащий тип является универсальным, вложенный тип эффективно параметризуется содержащим типом, например. Outer<int>.Nested не то же самое, что Outer<string>.Nested.
  • Вложенные типы имеют доступ к закрытым членам содержащего типа.
person Jon Skeet    schedule 08.10.2008
comment
(около 7 лет спустя...) Есть ли у вас идеи, почему внешний класс не может получить доступ к закрытым или защищенным членам вложенного класса точно так же, как вложенный класс может получить доступ к членам внешнего класса? Были времена, когда это было бы полезно, и мне интересно, был ли недостаток в моем дизайне. - person GDS; 29.06.2015
comment
@GDS: я не знаю, почему было принято это дизайнерское решение, но обычно оно имело для меня смысл. Если вы сделаете вложенный класс закрытым, то, в конце концов, можно сделать его члены внутренними или общедоступными. - person Jon Skeet; 29.06.2015
comment
Это правильно, но разве не может быть случаев, когда вы хотели бы, чтобы внутренний или даже общедоступный вложенный класс, но его частные и защищенные члены были видны внешнему классу? Есть ли в этом глубинный недостаток? - person GDS; 29.06.2015
comment
@GDS: Все, что я могу сказать, это то, что я сам не сталкивался с такими ситуациями. Я не могу предположить о точных причинах дизайна. - person Jon Skeet; 29.06.2015

В отличие от Java, в C# нет неявной ссылки на экземпляр окружающего класса.

Вам нужно передать такую ​​ссылку во вложенный класс. Типичный способ сделать это — через конструктор вложенного класса.

public partial class Form1 : Form
{
    private Nested m_Nested;

    public Form1()
    {
        InitializeComponent();

        m_Nested = new Nested(this);
        m_Nested.Test();
    }

    private class Nested
    {
        private Form1 m_Parent;

        protected Form1 Parent
        {
            get
            {
                return m_Parent;
            }
        }

        public Nested(Form1 parent)
        {
            m_Parent = parent;
        }

        public void Test()
        {
            this.Parent.textBox1.Text = "Testing access to parent Form's control";
        }
    }
}
person Jason Kresowaty    schedule 08.10.2008
comment
По-видимому, это также имеет то преимущество, что, в отличие от Java, экземпляр внутреннего класса может обращаться к закрытым членам любого экземпляра внешнего класса, а не только к экземпляру внешнего класса, создавшему внутренний класс. экземпляр класса (т. е. Form1 form = new Form1(); new Nested(form); является допустимым. - person Stevens Miller; 12.02.2018

Статические члены

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

class OuterClass
{
    private static int memberVar;

    class NestedClass 
    {
        void SomeFunction() { OuterClass.memberVar = 42; }
    }
}

Примечание: я намеренно (и избыточно) пометил memberVar как private, чтобы проиллюстрировать данную возможность вложенного класса для доступа к закрытым членам своего внешнего класса.

Осторожно / Пожалуйста, учтите

В некоторых ситуациях это может быть самым простым способом/обходным решением для получения доступа, но...

  • Статический также означает, что переменная будет совместно использоваться всеми объектами экземпляра со всеми недостатками/последствиями (потокобезопасность и т. д.).

  • Статический также означает, что это, очевидно, не будет работать, если у вас есть более одного экземпляра родительского класса, и переменная должна содержать отдельное значение для каждого экземпляра.

Поэтому в большинстве случаев вы можете использовать другой подход...

Передача ссылки

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

class OuterClass
{
    private int memberVar;
    private NestedClass n;

    OuterClass()   { n = new NestedClass(this); }


    class NestedClass
    {
        private OuterClass parent;

        NestedClass(OuterClass p) { parent = p; }
        SomeFunction() { parent.memberVar = 42; }
    }
}
person Levite    schedule 16.04.2015

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

class Outer()
{
    protected int outerVar;
    class Nested() : Outer
    {
        //can access outerVar here, without the need for a 
        // reference variable (or the associated dot notation).
    }
}

Я использовал этот метод, особенно в контексте структурированных модульных тестов. . (Это может не относиться к конкретному вопросу OP, но может быть полезно для вложенных классов в целом, как в случае с этим «дублирующимся» вопросом: « Могу ли я получить доступ к объектам внешнего класса во внутреннем классе ")

person kmote    schedule 28.07.2014
comment
Теперь это интересная идея и немного отличается от других ответов. Однако я почти уверен, что вы не можете создать подкласс существующего экземпляра объекта, поэтому, если у вас уже есть экземпляр Outer и вам нужен экземпляр Nested, соответствующий вашему существующему экземпляру Outer, я не могу Не думаю, что это работает. - person Sam; 27.03.2015
comment
Проблема здесь в том, что создание нового экземпляра Nested вызовет ctor внешнего класса, что, скорее всего, приведет к переполнению стека. - person BillW; 29.11.2016

Поправьте меня, если я ошибаюсь, вы пытаетесь обработать внешний элемент управления из внутреннего класса, поэтому вы столкнулись с этим. Лучшим способом сделать это было бы вести дела в событийно-ориентированной манере. Используйте шаблон Observer, зарегистрируйте слушателя на внешнем элементе управления (ваш вложенный/внутренний класс будет слушателем). Делает жизнь проще. Боюсь, это не тот ответ, которого вы ожидали!

person questzen    schedule 08.10.2008

Вы можете передать окружающий класс в качестве параметра конструктору вложенного класса, например:

private NestedClass _nestedClass;
public ParentClass() 
{
   _nestedClass = new NestedClass(this);
}

Вложенные классы обычно не рекомендуются и должны быть закрытыми и/или внутренними. Хотя, на мой взгляд, они иногда полезны.

person mannu    schedule 08.10.2008

отправить мастер-класс в качестве параметра конструктора во вложенный (внутренний) класс.

person Hamid Jolany    schedule 22.09.2016

выше есть хороший ответ, но мне нравится писать что-то.

вложенный класс С# по умолчанию является закрытым

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

person afshar003    schedule 31.05.2021