Более опытные программисты, расскажите о реальных практических случаях, когда требовалось использовать класс, вложенный в класс. Просто не получается пока понять, зачем это может потребоваться.
-
6А вас интересуют реальные примеры из реальной практики? Их есть, и много у кого. Только вот что вам даст, скажем так, субъективное объяснение? А объективно - если вы не чувствуете такой потребности - не используйте, делов-то. Как увидите, что надо - сразу поймёте, когда и зачем так делать. – kami Sep 11 '23 at 11:56
-
3к примеру, я в своей практике встречал дто , построенные с использованием вложенных классов. хорошо это или плохо - решать вам, но в целом выглядело довольно логично – Дмитрий Sep 11 '23 at 12:08
-
Возможный дубликат: Объявление класса/структуры внутри другого класса: достоинства и недостатки – Andrei Khotko Sep 11 '23 at 20:48
2 Answers
Из собственной практики, вложенные классы нужны как дополнительный способ инкапсуляции, чтобы "не выставлять наружу ненужный код", а использовать или нет эти возможности решать уже вам.
Один из примеров применения, это создание приватных наследников "внешнего" класса:
public class Outer
{
public static Outer CreateSomething() => return new Inner();
private class Inner : Outer { ... }
}
В данном случае Inner не будет виден за пределами Outer класса, позволяя скрывать внутреннюю реализвацию. Из практики было такое, например, у меня есть кастомная коллекция, которая реализует ICollection<T> назовем её MyCollection и у меня появилась необходимость расширить мою реализацию и добавить возможность сделать одну коллекцию родетелем другой, т.е. при вызове myCollection[key], я сначала проверяю дочернюю коллекцию и созвращаю елемент, если его нет, тогда проверяю родительскую.
И есть несколько способов это реализовать:
- все запихнуть в один класс - плохо, получается каша и далеко не всегда эта фича с родитель-потомок отношением нужна
- создать нового публичного наследника
MyScopedCollection, таким образом у меня появляется два класс, один в себе содержир реализацию коллекции, второй добовляет возможность добавлять её как родитель - создать нового приватного наследника
MyScopedCollection, аналогично предидущему пунтку, но дополнительно скрываем реализацию.
public class MyColletion : ICollection<...>
{
// реализация коллекции
public static MyColletion CreateChild(MyColletion parent)
=> new MyScopedCollection(parent);
private class MyScopedCollection : MyCollection
{
public MyScopedCollection(MyColletion parent) { ... }
}
}
// ...
var parent = new MyCollection { ... };
var child = MyColletion.CreateChild(parent);
Реализация паттерна Memento
Этот паттерн позмоляет сохранить внутренне состояние объекта не раскрывая его, а потом при необходимости восстановить обратно. Можно использовать немного измененный пример из википерии:
class Memento
{
private readonly string savedState;
private Memento(string stateToSave)
=> savedState = stateToSave;
public class Originator
{
private string state;
public void Set(string state)
=> this.state = state;
public Memento SaveToMemento()
=> new Memento(state);
public void RestoreFromMemento(Memento memento)
=> state = memento.savedState;
}
}
// ...
var originator = new Memento.Originator();
originator.Set("State1");
var oldState = originator.SaveToMemento();
originator.Set("State2");
originator.RestoreFromMemento(oldState);
// originator.state == "State1"
Originator содержит некоторое состояние, а Memento позволяет сохранить его. Т.е. у Memento приватный конструктор, то создать "потдельное" состояние, а потом вызвать RestoreFromMemento не получится. Но в тоже время вложенные класс Originator имеет доступ к приватным членам внешнего класса. Поэтому мы может его созлать в SaveToMemento методе.
И теретически можно ещё придумать кучу примеров, но надеюсь эти примеры помогут вам понять когда можно использовать вложенные классы.
- 5,462
В C# есть вариант реализации шаблона проектирования Singleton через вложенный класс, что позволяет сделать "ленивую" потокобезопасную инициализацию instance:
public class Singleton
{
public string Date { get; private set; }
public static string text = "hello";
private Singleton()
{
Console.WriteLine($"Singleton ctor {DateTime.Now.TimeOfDay}");
Date = DateTime.Now.TimeOfDay.ToString();
}
public static Singleton GetInstance()
{
Console.WriteLine($"GetInstance {DateTime.Now.TimeOfDay}");
return Nested.instance;
}
private class Nested
{
internal static readonly Singleton instance = new Singleton();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Main {DateTime.Now.TimeOfDay}");
Console.WriteLine(Singleton.text);
}
}
Конструктор Singleton пока не вызвался, он вызовется при первом обращении к Singleton.GetInstance().
- 71,194