Uniemożliwienie tworzenia obiektów klasy z jednym wyjątkiem

0

Czy jest jakaś możliwość w C#, uniemożliwienie tworzenia obiektów klasy, z wyjątkiem jednej, innej klasy. W C++ mógłbym dać prywatny konstruktor i firendi to załatwiło by sprawę.

A co chce osiągnąć: chce mieć taki jakby singleton, który jest dostępny jedynie z poziomu innej niestatycznej klasy. Innymi słowy: mam system logowania, który umożliwia jednocześnie zalogowanie tylko jednego użytkownika, za system logowania i zarządzania kontami odpowiada klasa: AccountManagement, chce aby miała ona właściwość CurrentUser, która zwraca ten mój singleton, ale chce również aby obiekt tej klasy nie mógł być tworzony nigdzie indziej oprócz klasy AccountManagement.

0

Zwykły singleton + internal class?

0

Nie mogę dać internal class, klasa AccountManagement, jest umieszczona w DLL i jest wykorzystywana w innych projektach, także internal class, powodowała by błąd poziomu dostępności.

1

Zawsze można użyć refleksji do sprawdzenia jaka klasa wywołuje daną metodę.
Tylko jaki jest cel tego wszystkiego? Chcesz się zabezpieczyć przed swoim błędem?

0

Zawsze byłem uczony żeby uniemożliwiać wykonanie wszystkiego co nie powinno być wykonane, tak jak w tym przypadku z oczywistych przyczyń nie chce aby dostęp do danych zalogowanego użytkownika były w globalnym zasięgu. Tak jest to pewien sposób zabezpieczenia, dziś z kodu korzystam tylko ja, ale nigdy nie wiadomo czy za rok tak będzie.

0

@spartanPAGE nie rozumiem Twojego toku rozumowania, co jest złego w tym aby zadbać o to aby coś co nie powinno być dostępne globalnie takie nie było?

Wracając do tematu, rozwiązanie nie okazało się skomplikowane, stworzyłem publiczną stealed klase CurrentUser z konstruktorem o dostępności internal, przez co nie mogę tworzyć tego obiektu w innych odwołaniach, ale mogę się do niego dobrać jedynie przez właściwość CurrentUserklasy AccountManagement - to tak dla potomnych.

1
Krwawy Krawiec napisał(a):

@spartanPAGE nie rozumiem Twojego toku rozumowania, co jest złego w tym aby zadbać o to aby coś co nie powinno być dostępne globalnie takie nie było?

Nic, poza tym, że chyba nie bardzo rozumiesz ideę zabezpieczania. Bo w sumie, to ani to nie zwiększa bezpieczeństwa aplikacji, ani nie sprawia, że programista popełni mniej błędów. Więc o co chodzi w tym "zabezpieczeniu"?

Wracając do tematu, rozwiązanie nie okazało się skomplikowane, stworzyłem publiczną stealed klase CurrentUser z konstruktorem o dostępności internal, przez co nie mogę tworzyć tego obiektu w innych odwołaniach, ale mogę się do niego dobrać jedynie przez właściwość CurrentUserklasy AccountManagement - to tak dla potomnych.

1) sealed nie ma wpływu na widoczność klasy.
2) Możesz utworzyć ten obiekt w każdej klasie z tego assembly, tak działa internal.
3) A w każdej innej klasie na świecie możesz zrobić po prostu:

var currentUser = typeof(CurrentUser).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single().Invoke(null) as CurrentUser;

Tyle z tego zabezpieczenia.

1

Jak dla mnie perełka, kod broniący się przed programistą - spartanPAGE dzisiaj, 10:37

Tak samo jak modyfikator private - niby jeśli ktoś się uprze/potrzebuje, można go obejść (w C++ również), ale to bardziej informacja dla programisty "nie dotykaj, szczegół implementacyjny".

Czy jest jakaś możliwość w C#, uniemożliwienie tworzenia obiektów klasy, z wyjątkiem jednej, innej klasy. W C++ mógłbym dać prywatny konstruktor i firend i to załatwiło by sprawę.

1) Ogólnie moim zdaniem może myślisz w dobrym kierunku, ale idziesz w złą stronę. Jeśli klasa jest publiczna - mogą ją stworzyć wszyscy. Friend i inne wynalazki tylko tworzą kolejny poziom skomplikowania i niejawne powiązania między klasami, które komplikują sytuację - nie bez powodu ich w końcu w C# nie ma.
2) Jeśli martwi Cię kto ma tworzyć ten obiekt - zastanów się na przykład czy jakieś dependency injection by Ci nie ułatwiło sytuacji.
3) I ogólnie, nie ma co przesadzać i zakładać że każdy programista piszący kod w Twoim projekcie nic nie robi poza myśleniem jak wprowadzić błędy.

Jeśli chodzi o temat, coś co faktycznie uniemożliwia tworzenie obiektu (pierwsza myśl przynajmniej):

class SecureClass
{
    public SecureClass()
    {
        StackTrace trace = new StackTrace();
        StackFrame frame = trace.GetFrame(1); // z jakiej metody został wywołany ten konstruktor
        if (frame.GetMethod().DeclaringType != typeof(Ok)) // jeśli metoda jest w złej klasie
        { 
            throw new InvalidOperationException("Nope"); // rzucamy błąd
        }
    }
}

Ale nie używaj tego, naprawdę (bo to faktycznie kod wrogi programiście, i lista problemów z tym by była tak długa że nawet nie zaczynam pisać).

0

Jest jeszcze taka opcja, żeby stworzyć interfejs np. IUser i ustalić go jako typ dla CurrentUser. A klasę, która go implementuje ukryć jako prywatną w AccountManagement.
Ogólnie to co chcesz zrobić brzmi dziwnie. Nie wystarczy prywatny setter dla CurrentUser, żeby nie można ustawić tego pola poza klasą? Wtedy AccountManagement będzie mieć pełną kontrolę nad tworzeniem tego obiektu i czasem kiedy to ma się stać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0