[C#] как сделать синглетон? (ЗАКРЫТО)

kruzer25

Я тут уже все мозги сломал, пытаясь придумать, как бы решить эту проблему... наверняка в мсдн что-то про это написано, но надо придумать, по каким ключевым словам искать...
using System;
using System.Collections.Generic;
//using System.Linq;
//using System.Text;

namespace xxx {

abstract class CAbstractSingleton {

private static Dictionary<Type, CAbstractSingleton> hInstances = new Dictionary<Type, CAbstractSingleton>

protected static CAbstractSingleton getInstanceOf(Type tClassName) {
if(!(tClassName.IsSubclassOf(typeof(CAbstractSingleton throw new ArgumentException("Trying to instance not-singleton '" + tClassName.ToString + "'", "tClassName");
if(!CAbstractSingleton.hInstances.ContainsKey(tClassName {
Object oCreatedSingleton = Activator.CreateInstance(tClassName);
if(oCreatedSingleton is CAbstractSingleton) {

//Workaround for VS notifies
//We will be here only one time for each used Singleton class, so performance here isn't so important
// CAbstractSingleton oFixedCreatedSingleton = (CAbstractSingleton)oCreatedSingleton;

----> CAbstractSingleton.hInstances.Add(tClassName, oCreatedSingleton);
} else {
throw new ApplicationException("When constructing '" + tClassName.ToString + "', got object of '" + oCreatedSingleton.GetType.ToString + "'");
}

}

return CAbstractSingleton.hInstances[tClassName];
}

}

}

Что естественно - выдаётся ошибка
Error 1 The best overloaded method match for 'System.Collections.Generic.Dictionary<System.Type,xxx.CAbstractSingleton>.Add(System.Type, xxx.CAbstractSingleton)' has some invalid arguments C:\Users\xxx\Documents\Visual Studio 2008\Projects\xxx\xxx\CAbstractSingleton.cs 22 21 xxx
и
Error 2 Argument '2': cannot convert from 'object' to 'xxx.CAbstractSingleton' C:\Users\xxx\Documents\Visual Studio 2008\Projects\xxx\xxx\CAbstractSingleton.cs 22 67 xxx
, в результате - ничего не компилируется.
Как ей можно сказать, что oCreatedSingleton всё-таки является объектом CAbstractSingleton?
Закоменченную строчку не проверял, но выглядит уж очень страшно, и кажется, что преобразование CConcreteSingleton в CAbstractSingleton ни к чему хорошему не приведёт.
Да, и ещё - это я тут, может быть, просто пытаюсь всё сделать, как в пхп, а на самом деле всё это реализуется в C# в две строчки, если ещё не входит в BCL? Правда, в мсдн ничего полезного по запросу singleton найти не удалось.

kruzer25

Ну и такой же вопрос про:
using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;

namespace xxx {

class CConcreteSingleton : CAbstractSingleton {

public static CConcreteSingleton getInstance {
return CConcreteSingleton.getInstanceOf(typeof(CConcreteSingleton;
}

}

}

Получаем:
Error 1 Cannot implicitly convert type 'xxx.CAbstractSingleton' to 'xxx.CConcreteSingleton'. An explicit conversion exists (are you missing a cast?) C:\Users\xxx\Documents\Visual Studio 2008\Projects\xxx\xxx\CConcreteSingleton.cs 11 20 xxx
Наверняка ведь есть какой-нибудь способ сказать что-нибудь вроде AssertIs(Object, Type чтобы потом уже жить спокойно и чтобы компилятор-редактор ничего не говорили на попытки использовать объект в соответствии с этим типом?

Dasar

return CConcreteSingleton.getInstanceOf(typeof(CConcreteSingleton;

return (CConcreteSingleton)CConcreteSingleton.getInstanceOf(typeof(CConcreteSingleton;

еще лучше getInstanceOf делать Generic и эту проверку переносить туда
тогда будет

return CConcreteSingleton.getInstanceOf<CConcreteSingleton>(typeof(CConcreteSingleton;

или вообще

return CConcreteSingleton.getInstanceOf<CConcreteSingleton>

Alexander08

ну и прогай дальше на пхп, сишарп видать не твое, как и вобщем - ООП.

Dasar

а вообще не хера непонятно зачем такое городится (особенно если учесть что код получился к тому же потоко-небезопасный
если нормальный синглетон делается так:
[class]
class CConcreteSingleton
{
  public static readonly CConcreteSingleton Instance = new CConcreteSingleton;
}
[/class]

kruzer25

особенно если учесть что код получился к тому же потоко-небезопасный
Это пока что неважно :)
если нормальный синглетон делается так:
Ага, и:
1) Какая-то не очень хорошая защита получается от того, что этот объект поменяют снаружи (хотя и есть какая-то защита в виде того, что конструктор закрыт, но тем не менее);
2) И когда все эти синглтоны заистанцируются? При запуске программы? В каком порядке они это сделают? Что, если конструктор одного синглтона будет использовать другой? В моей схеме всё будет работать, пока не будет кривых зависимостей (конструктор А использует Б в то время как конструктор Б использует А); а в твоём - видимо, не будет работать вообще.
Про generic-и сейчас читаю, пока что понятно только, что можно с их помощью сделать так, чтобы тип возврата getInstanceOf определялся при его вызове из конкретного getInstance; но непонятно, как можно избавиться от дублирования аргументов (чтобы писать, как ты сказал, CAbstractSingleton.getInstanceOf<CConcreteSingleton и как решить первую проблему...
Читаю дальше...

kruzer25

О, наткнулся на пример, получается, мы можем использовать тип, который в угловых скобках - и в коде?
public static T Factory<T> where T:new 
{
return new T;
}

kruzer25

Вообще, похоже, хрошая вещь эти generic-и...

kruzer25

сишарп видать не твое
На основании чего ты сделал такой вывод?

kruzer25

Ага, спасибо, задача наверняка решается именно так.
Но код
    abstract class CAbstractSingleton {

private static Dictionary<Type, CAbstractSingleton> hInstances = new Dictionary<Type, CAbstractSingleton>

abstract public static CAbstractSingleton getInstance;

protected static tClass getInstanceOf<tClass> where tClass : CAbstractSingleton, new {
if(!CAbstractSingleton.hInstances.ContainsKey(typeof(tClass {
CAbstractSingleton.hInstances.Add(typeof(tClass new tClass;
}

return CAbstractSingleton.hInstances[typeof(tClass)];
}

}


, что вполне естественно, не работает - в выражении return возвращается-то не tClass, а просто CAbstractSingleton.
Думаю дальше...

kruzer25

Оказывается, всё-таки можно делать так:
In the example above, class B is effectively both B and A. When you access a B object, you can use the cast operation to convert it to an A object. The B object is not changed by the cast, but your view of the B object becomes restricted to A's data and behaviors. After casting a B to an A, that A can be cast back to a B. Not all instances of A can be cast to B—just those that are actually instances of B. If you access class B as a B type, you get both the class A and class B data and behaviors.
Но как-то это грязно...

kokoc88

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

kruzer25


class CConcreteSingleton {
public static readonly CConcreteSingleton Instance = new CConcreteSingleton;
}

class COtherSingleton : CConcreteSingleton {
public COtherSingleton { }
}

class EvilDoer {
public void DoEvil {
CConcreteSingleton.Instance = new COtherSingleton;
}
}

Разве не сработает?
UPD: Не заметил слово readonly :o
Тем не менее, остальные минусы такого подхода остаются.

kokoc88

И когда все эти синглтоны заистанцируются? При запуске программы? В каком порядке они это сделают? Что, если конструктор одного синглтона будет использовать другой? В моей схеме всё будет работать, пока не будет кривых зависимостей (конструктор А использует Б в то время как конструктор Б использует А); а в твоём - видимо, не будет работать вообще.
C# - это не php, здесь за тебя обо всём подумали. Статические конструкторы вызываются во время доступа к типу. Прежде чем начинать дискуссию, стоит прочитать какую-нибудь книжку по языку.

klyv

И когда все эти синглтоны заистанцируются? При запуске программы? В каком порядке они это сделают? Что, если конструктор одного синглтона будет использовать другой? В моей схеме всё будет работать, пока не будет кривых зависимостей (конструктор А использует Б в то время как конструктор Б использует А); а в твоём - видимо, не будет работать вообще.
В этом подходе всё будет так же работать, как и в твоём, но код занимает гораздо меньше места.

kokoc88

Тем не менее, остальные минусы такого подхода остаются.
Существенные минусы есть только в твоём подходе. Доступ не потокобезопасный, долгий, не предусмотрено создание класса, который не имеет конструктор по умолчанию. В то время как можно сделать синглтон с быстрым доступом и ленивой инициализацией.

Dasar


return (tClass)CAbstractSingleton.hInstances[typeof(tClass)];

kruzer25

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

kokoc88

В этом-то и проблема, что под рукой нет никаких книжек, только мсдн. А решить задачу надо.
Ну так набери в гугле "C# singleton" и почитай. Или не спорь с теми, кто читал книжки и знает, что делает.

kruzer25

Доступ не потокобезопасный, долгий, не предусмотрено создание класса
Да я уже понял, что тот подход вроде как лучше, потому что там уже всё предусмотрено... но жопой чую, что что-то тут не так.
МБ со временем это пройдёт... :grin:

kruzer25

return (tClass)CAbstractSingleton.hInstances[typeof(tClass)];
Я уже знаю, что так можно сделать, написал об этом в одном из предыдущих постов; но разве так - прилично делать?

kruzer25

Хм, про гугл я и не подумал :o

zya369

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

zya369

Хм, про гугл я и не подумал :o

ты, походу, вообще не [по]думал

kruzer25

Вы слишком многого от меня хотите, чтобы я первую свою программу на сишарпе писал с использованием всех его фич и забыв про то, что я делал раньше?
Уж лучше пусть пока будет максимально приближённое к тому, к чему я уже привык, а потом постепенно буду переходить на эти ваши новые фичи :)

Dasar

Я уже знаю, что так можно сделать, написал об этом в одном из предыдущих постов; но разве так - прилично делать?
почему нет?
ты как разработчик функции гарантируешь, что данный элемент словаря будет именно этого типа и данной конструкцией ты это рассказываешь компилятору.
соответственно - если ты компилятор обманешь, то просто будет exception.

kruzer25

В общем-то, я так уже и сделал; но, исходя из того, что я уже прочитал про сишарп, там очень много чего можно сделать так, чтобы проверки проходили на уровне компиляции; тут же получается, что я от этого отказываюсь и занимаюсь не очень понятным шаманизмом с приведением типов. Наверное, есть какой-нибудь выход?
Хотя, раз уж это можно решить так как ты сказал (с public static Instance = ... то, наверное, с таким извратом просто никто незаморачивался - чтобы достали чего-то из хэша, а оно оказалось конкретного типа.

kruzer25

гарантируешь, что данный элемент словаря будет именно этого типа и данной конструкцией ты это рассказываешь компилятору
А разве эта конструкция только объясняет компилятору про тип результата? Она же, наверное, ещё и преобразует объект в некоторых случаях? Или меня подводит семантика привычного языка?

Dasar

А разве эта конструкция только объясняет компилятору про тип результата?
в данном случае, только это
Она же, наверное, ещё и преобразует объект в некоторых случаях? Или меня подводит семантика привычного языка?
да, она может неявно вызывать оператор преобразования (если он есть но такое поведение не принято в .net.

6yrop

ты бы почитал соглашения по именованию для C#, а то методы с маленькой буквы, Object с большой, и какие-то буковки C.

kruzer25

Мне сейчас надо написать программу на распространённом языке; мне привычен PHP, но он, конечно, не подходит; на C или C++ я сойду с ума от управления памятью, а из Java и C# я выбрал то, что всё равно в ближайшем будущем пригодится - C#.
Давайте я пока что не буду заморачиваться ещё и правильным именованием в C#? :)

6yrop

Давайте я пока что не буду заморачиваться ещё и правильным именованием в C#?
ну и зря, к таким мелочам лучше сразу привыкать, переучиваться сложнее. И потом твой код никто не будет читать, сразу впечатление, что ламер писал...

klyv

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

kruzer25

к таким мелочам лучше сразу привыкать, переучиваться сложнее
Переучиваться с нынешнего стиля именования мне в любом случае придётся; и, наверное, лучше переучиваться тогда, когда я начну активно использовать C# и перестану использовать PHP?
Оставить комментарий
Имя или ник:
Комментарий: