Здравствуйте. В проекте использую синглтон (хотя я не совсем понимаю, как его правильно применять).
public sealed class DataManager
{
private DataManager()
{
Fabric = new FabricRepository();
FabricProduct = new FabricProductRepository();
Fitting = new FittingRepository();
FittingProduct = new FittingProductRepository();
Order = new OrderRepository();
ProductOrder = new ProductOrderRepository();
Product = new ProductRepository();
StockFabric = new StockFabricRepository();
StockFitting = new StockFittingRepository();
User = new UserRepository();
}
public FabricRepository Fabric { get; set; }
public FabricProductRepository FabricProduct { get; set; }
public FittingRepository Fitting { get; set; }
public FittingProductRepository FittingProduct { get; set; }
public OrderRepository Order { get; set; }
public ProductOrderRepository ProductOrder { get; set; }
public ProductRepository Product { get; set; }
public StockFabricRepository StockFabric { get; set; }
public StockFittingRepository StockFitting { get; set; }
public UserRepository User { get; set; }
static DataManager _active = null;
public static DataManager Instance
{
get
{
if (_active == null)
_active = new DataManager();
return _active;
}
}
}
То есть он лежит у меня в одном месте с моими репозиториями, через него я к ним и обращаюсь. Вот код конструктора моего generic repository
public BaseRepository()
{
this.TableName = typeof(T).Name;
FillTable();
}
private void FillTable()
{
DataAdapter.SelectCommand = new SqlCommand("SELECT * FROM [" + this.TableName + "]", Config.con);
DataAdapter.Fill(this.Table);
}
Правильно ли я понимаю, что при создании например в коде формы DataManager.Instance.User.Add(user)
он проходит по всем конструкторам моих репозиториев и заполняет данными? То есть, при наличии даже небольшого числа данных будет задержка. Может просто создавать этот синглтон по мере необходимости? Буду благодарен за любые советы.
Он у вас и создаётся по необходимости - при первом обращении.
Вы можете сделать синглтоном каждый репозиторий в отдельности, и обращаться к ним так:
User.Instance.Add(...);
Product.Instance.Add(...);
Или сделать отложенное создание этих свойств. Пример отложенной инициализации поля Instance вы привели самостоятельно. Ничто не мешает поступить так же со всеми остальными.
Можно пойти ленивым путём и с небольшим оверхедом использовать готовое средство: Lazy
.
В любом случае, как вам верно заметили, проблема проистекает из-за загрузки данных при вызове конструктора. Это очень плохое решение. Конструктор не должен содержать сложной логики, длительных или прожорливых операций.
Если по какой-то причине данные нужно загрузить один раз и держать постоянно в памяти - способ отложенной загрузки вы теперь знаете.
Вообще на практике довольно редко приходится реализовывать синглтон. Обычно синглтонами делают классы на этапе настройки IoC контейнера. Например, у нас есть класс
public class IAmSingletone
{
private bool _initialized = false;
private object _lock = new Object();
public IAmSingletone()
{
Console.WriteLine("IAmSingletone created");
}
private void LoadALotOfData()
{
if (!_initialized)
{
lock (_lock)
{
if (!_initialized)
{
Console.WriteLine("Doing loading stuff...");
Thread.Sleep(3000);
Console.WriteLine("Stuff loaded.");
_initialized=true;
}
}
}
}
public void DoWork()
{
LoadALotOfData();
Console.WriteLine("Doing DoWork");
}
}
Видно, что классу надо чтото грузить для работы, но он это делает только тогда, когда эти данные реально нужны для выполнения операций. То есть создание синглтона быстрое, загрузка данных выполняется при первом обращении к методу. Теперь нарисуем клиента
public class IAmClient
{
IAmSingletone _singletone;
public IAmClient(IAmSingletone singletone)
{
_singletone = singletone;
Console.WriteLine("Creating client.");
}
public void CallForSongletone()
{
Console.WriteLine("Calliong _singletone.DoWork()");
_singletone.DoWork();
}
}
С клиентом все и так ясно - получает нужный ему класс и вызывает его методы когда надо. Теперь как это связать. (я использовал контейнер CastleWindsor)
var container = new WindsorContainer();
container.Register(Component.For<IAmSingletone>().LifeStyle.Singleton);
container.Register(Component.For<IAmClient>().LifeStyle.Transient);
for (var i = 0; i < 5; i++)
{
var client = container.Resolve<IAmClient>();
client.CallForSongletone();
}
Как видно, синглтон зарегестрирован как синглтон, обычный класс- как обычный класс. Вывод на консоль будет:
IAmSingletone created
Creating client.
Calliong _singletone.DoWork()
Doing loading stuff...
Stuff loaded.
Doing DoWork
Creating client.
Calliong _singletone.DoWork()
Doing DoWork
Creating client.
Calliong _singletone.DoWork()
Doing DoWork
Creating client.
Calliong _singletone.DoWork()
Doing DoWork
Creating client.
Calliong _singletone.DoWork()
Doing DoWork
Из вывода видно, что синглтон создан 1 раз, данные загружены 1 раз, и это для 5 разных клиентов. Преимущество этого метода - вы можете переключать время жизни объекта с обычного класса на синглтон и обратно просто меняя настройку IoC контейнера.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Задача состоит в записи параметров в таблицуНе выходит записать по неизвестной причине
По умолчанию VS при компиляции кладет все в одну директорию рядом с EXE
Как привязать свой VScrollBar к TableLayout панели?