C # bir singleton nedir?


182

Singleton nedir ve ne zaman kullanmalıyım?



4
Ayrıca, Singleton, OO programlamasında en yaygın kullanılan ve istismar edilen tasarım modellerinden biridir.
ChaosPandion

3
@Fabiano: Çünkü hiçbir anlam ifade etmeyen (nasıl Xkonuşabilirim Y? Sadece Ybir singleton yapın!) Kaplinler oluşturmanın bir yolu vardır , bu da test / hata ayıklamada zorluklara ve prosedürel bir programlama stiline yol açar. Bazen Singletons gereklidir; çoğu zaman değil.
Aaronaught

3
Bu, standart telefon görüşmesi sorularımdan biri. Doğru cevap: asla.
Ocak'ta jonnii

3
@jonnii bu iyi, potansiyel geliştiriciler patron gibi ne olduğunu uyarmak yardımcı olur!
Bay Boy

Yanıtlar:


145

Singleton, yalnızca bir örneğinin oluşturulmasına izin veren ve söz konusu örneğe basit ve kolay erişim sağlayan bir sınıftır. Tekton öncül, yazılım geliştirmede bir modeldir.

İş parçacığı güvenliği ile ilgili bazı iyi tavsiyeler de dahil olmak üzere bilmeniz gerekenlerin çoğunu kapsayan "C # 'da Singleton Kalıbını Uygulama" adlı bir C # uygulaması vardır .

Dürüst olmak gerekirse, bir singleton uygulamanız çok nadirdir - bence çok sık kullanılmasa bile, bilmeniz gereken şeylerden biri olmalıdır.


2
güzel öğretici ama kutsal bok ne kod girintisi için yaptım
Inspi

İşte "I 2020 yılında İdeal uygulama olarak kabul ettiğimiz için daha doğrudan bir bağlantı var .NET 4 en Tembel <T> türünü kullanarak hem Microsoft Doc bağlantı olarak," Lazy<T> Class.
Chiramisu

52

C # istediniz. Önemsiz örnek:


public class Singleton
{
    private Singleton()
    {
        // Prevent outside instantiation
    }

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}

14
iki iş parçacığı aynı anda çağırabilir ve iki ayrı nesne oluşturabilir.
Alagesan Palani

5
@Alagesan Palani, haklısın. Sınıf düzeyinde başlatmanın düşük düzeyli ayrıntılarında yetkin değilim, ancak yaptığım değişikliğin iş parçacığı açısından güvenli endişeye işaret ettiğini düşünüyorum.
Chris Simmons

3
emin, yanlış olduğunu işaret ETMİYORUM. okuyucuya iplik güvenliği hakkında bir ipucu veriyorum, böylece onunla başa çıkmak zorunda kalırlarsa dikkatli olurlar.
Alagesan Palani

9
Hayır, bence yorumunuz önemli. Bir singletonun bir ve sadece bir örnek vermesi gerektiği göz önüne alındığında, buradaki yarış koşulu birden fazla teslim edilme olasılığını açar. Statik alan başlatma ile şimdi sürüme bakın. Dokümanları okursam ve bu SO cevabını doğru bir şekilde okursam, iş parçacığının güvenlik sorununu giderdiğine inanıyorum .
Chris Simmons

1
@AlagesanPalani, görüyorum ki, birkaç cevap daha güvenli değil. İş parçacığı açısından güvenli bir çözüm sunmak ister misiniz?
Bonez024

39

Nedir? Bir uygulamanın ömrü boyunca yalnızca bir, kalıcı örneği olan bir sınıf. Bkz. Singleton Kalıbı .

Ne zaman kullanmalısınız: Mümkün olduğunca az. Sadece ihtiyacınız olduğundan kesinlikle eminseniz. "Asla" demeye isteksizim, ama genellikle Bağımlılık Enjeksiyonu veya sadece statik bir sınıf gibi daha iyi bir alternatif var.


16
Statik bir sınıfın bir singletondan daha iyi bir alternatif olduğundan emin değilim ... gerçekten duruma ve dile bağlı.
Ocak'ta marcgg

5
Statik sınıflar tekil birton gibi davranmaz, tekil bir parametre olarak yöntemlere geçirilirken statik sınıf olamaz.
TabbyCool

4
Marcgg ile aynı fikirdeyim - Statik bir sınıfı tek tektonlara iyi bir alternatif olarak görmüyorum, çünkü hala bir ikame sağlama probleminiz var, örneğin bu sınıfa bağlı bir bileşenin test edilmesi sırasında. Ama aynı zamanda farklı kullanımları da görüyorum, statik sınıf tipik olarak durumdan bağımsız, tek bir sınıfın gerçek bir sınıf örneği olduğu bağımsız yardımcı işlevler için kullanılır ve tipik olarak bir durum depolardı. Onun yerine DI kullanmayı tamamen kabul ediyorum ve sonra DI konteynerinize sadece o sınıfın tek bir örneğini kullanmasını istediğinizi söylüyorum.
Pete

9
Bu cevabı iptal ettim çünkü bana ne zaman kullanılacağına dair hiçbir bilgi vermiyor. "Sadece ihtiyacınız olduğunda" tek başına yeni başlayan birisi için bana hiçbir bilgi vermiyor.
Sergio Tapia

9
@Adkins: DI, herhangi bir sınıf bağımlılığının (genellikle) bir kurucudan veya genel mülkten geçirildiği Bağımlılık Enjeksiyonu anlamına gelir. Yalnızca DI "mesafe" sorununu çözmez, ancak genellikle herhangi bir bağımlılığın otomatik olarak nasıl başlatılacağını bilen bir Kontrol Ters Çevirme (IoC) kabının yanında uygulanır. Eğer "X, Y'yi nasıl bulacağını / konuşacağını bilmiyor" problemini çözmek için bir Singleton oluşturuyorsanız, DI ve IoC kombinasyonu aynı sorunu daha gevşek kuplajla çözebilir.
Aaronaught

27

singleton c # uygulamak için başka bir yol, kişisel olarak bu yolu tercih çünkü singeton sınıf örneğine bir yöntem yerine bir özellik olarak erişebilirsiniz.

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }

        //instance methods
    }

ama iyi, bildiğim kadarıyla her iki yol da 'doğru' sayılıyor bu yüzden bu sadece kişisel bir lezzet.


11
iki iş parçacığı aynı anda çağırabilir ve iki ayrı nesne oluşturabilir.
Alagesan Palani

11
using System;
using System.Collections.Generic;
class MainApp
{
    static void Main()
    {
        LoadBalancer oldbalancer = null;
        for (int i = 0; i < 15; i++)
        {
            LoadBalancer balancerNew = LoadBalancer.GetLoadBalancer();

            if (oldbalancer == balancerNew && oldbalancer != null)
            {
                Console.WriteLine("{0} SameInstance {1}", oldbalancer.Server, balancerNew.Server);
            }
            oldbalancer = balancerNew;
        }
        Console.ReadKey();
    }
}

class LoadBalancer
{
    private static LoadBalancer _instance;
    private List<string> _servers = new List<string>();
    private Random _random = new Random();

    private static object syncLock = new object();

    private LoadBalancer()
    {
        _servers.Add("ServerI");
        _servers.Add("ServerII");
        _servers.Add("ServerIII");
        _servers.Add("ServerIV");
        _servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
        if (_instance == null)
        {
            lock (syncLock)
            {
                if (_instance == null)
                {
                    _instance = new LoadBalancer();
                }
            }
        }

        return _instance;
    }

    public string Server
    {
        get
        {
            int r = _random.Next(_servers.Count);
            return _servers[r].ToString();
        }
    }
}

Ben dofactory.com kodu aldı , çok süslü bir şey ama bu Foo ve Bar ile örnekleri çok iyi buluyorum Ayrıca Judith Bishop C # 3.0 Design Patterns kitap mac dock aktif uygulama hakkında örnek var.

Eğer koda bakarsanız, aslında döngü için yeni nesneler inşa ediyoruz , böylece yeni nesne oluşturur, ancak eski dengeleyici ve yeni dengeleyicinin aynı örneğe sahip olması nedeniyle örneği yeniden kullanır, Nasıl? GetLoadBalancer () işlevinde kullanılan statik anahtar nedeniyle , rasgele liste olan farklı sunucu değerine sahip olmasına rağmen, GetLoadBalancer () üzerindeki statik, belirli bir nesneye değil, türün kendisine aittir.

Ayrıca orada kilit çifte kontrol buraya

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)

MSDN'den beri

Lock anahtar sözcüğü, bir iş parçacığının kritik bölümdeyken bir iş parçacığının önemli bir kod bölümüne girmemesini sağlar. Başka bir iş parçacığı kilitli bir kod girmeye çalışırsa, nesne serbest bırakılıncaya kadar bekler, engeller.

bu yüzden her seferinde karşılıklı dışlama kilidi verilir, buna gerek kalmasa bile gereksizdir, bu yüzden null kontrolümüz vardır.

Umarım daha fazla temizlemeye yardımcı olur.

Ve lütfen benim anlayışım yanlış yolları yönlendiriyorsa yorum yap.


6

Bir Singleton (ve bu C # ile bağlantılı değildir, bu bir OO tasarım modelidir) uygulamanız boyunca bir sınıfın yalnızca BİR örneğinin oluşturulmasına izin vermek istediğiniz zamandır. Kullanımlar tipik olarak küresel kaynakları içerecektir, ancak kişisel deneyimlerden söyleyeceğim, ancak bunlar genellikle büyük acı kaynağıdır.


5

Tek birtonun sadece bir örneği olsa da, statik bir sınıfla aynı değildir. Statik bir sınıf yalnızca statik yöntemler içerebilir ve hiçbir zaman somutlaştırılamaz, oysa bir singleton örneği başka herhangi bir nesne ile aynı şekilde kullanılabilir.


2

Bu bir tasarım deseni ve c # 'a özgü değil. Bu wikipedia makalesinde olduğu gibi tüm internet ve SO hakkında daha fazla bilgi .

Yazılım mühendisliğinde, tekli desen, bir sınıfın bir nesneyle örneklenmesini kısıtlamak için kullanılan bir tasarım modelidir. Sistemdeki eylemleri koordine etmek için tam olarak bir nesne gerektiğinde bu yararlıdır. Kavram bazen yalnızca bir nesne olduğunda daha verimli çalışan veya somutlaştırmayı belirli sayıda nesneyle sınırlayan sistemlere genelleştirilir (örneğin, beş). Bazıları bunu bir anti-model olarak kabul eder, aşırı kullanıldığını düşünür, bir sınıfın tek bir örneğinin gerçekten gerekli olmadığı durumlarda gereksiz sınırlamalar getirir ve küresel durumu bir uygulamaya sokar.

Sadece bir kez örneklenebilecek bir sınıf istiyorsanız bunu kullanmalısınız.


2

Arama verileri için kullanıyorum. DB'den bir kez yükleyin.

public sealed class APILookup
    {
        private static readonly APILookup _instance = new APILookup();
        private Dictionary<string, int> _lookup;

        private APILookup()
        {
            try
            {
                _lookup = Utility.GetLookup();
            }
            catch { }
        }

        static APILookup()
        {            
        }

        public static APILookup Instance
        {
            get
            {
                return _instance;
            }
        }
        public Dictionary<string, int> GetLookup()
        {
            return _lookup;
        }

    }

2

Tekil nedir:
Kendisinin yalnızca bir örneğinin oluşturulmasına izin veren ve genellikle bu örneğe kolay erişim sağlayan bir sınıftır.

Ne zaman kullanmalısınız:
Duruma göre değişir.

Not: Lütfen db bağlantısında kullanmayın, ayrıntılı bir cevap için lütfen @Chad Grant'in cevabına bakın .

İşte basit bir örnek Singleton:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

Ayrıca Lazy<T>oluşturmak için kullanabilirsiniz Singleton.

Kullanarak daha ayrıntılı bir örnek için buraya bakınLazy<T>



1

Singleton sınıfı, tüm uygulama etki alanı için tek bir örnek oluşturmak için kullanılır.

public class Singleton
{
    private static Singleton singletonInstance = CreateSingleton();

    private Singleton()
    {
    }

    private static Singleton CreateSingleton()
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

    public static Singleton Instance
    {
        get { return singletonInstance; }            
    }
}

Gelen bu makalede açıklanır biz salt okunur değişken ve uygulamalarda pratik kullanımını kullanarak iş parçacığı güvenli tekil sınıfı oluşturmak nasıl.


1

Soruyu cevaplamak için çok geç olduğunu biliyorum, ancak Auto-Property ile böyle bir şey yapabilirsiniz:

public static Singleton Instance { get; } = new Singleton();

Nerede Singletonsınıflandırılıyorsunuz ve bu durumda salt okunur özellik olabilir Instance.


0

EX Enjekte edilmesi gereken global bilgiler için Singleton kullanabilirsiniz.

Benim durumumda, Günlüklü kullanıcı ayrıntılarını (kullanıcı adı, izinler vb.) Global Statik Sınıfta tutuyordum. Birim Testini uygulamaya çalıştığımda, Controller sınıflarına bağımlılık enjekte edebilmem mümkün değildi. Böylece Statik Sınıfımı Singleton modeline değiştirdim.

public class SysManager
{
    private static readonly SysManager_instance = new SysManager();

    static SysManager() {}

    private SysManager(){}

    public static SysManager Instance
    {
        get {return _instance;}
    }
}

http://csharpindepth.com/Articles/General/Singleton.aspx#cctor


0

Belirli bir sınıfın yalnızca bir örneğinin oluşturulmasını ve ardından tüm uygulama için bu örneğe basit küresel erişim sağlamamız gerektiğinde C # 'daki Singleton Tasarım Deseni'ni kullanmamız gerekir.

Singleton Tasarım Deseni: Hizmet Proxy'lerini kullanabileceğiniz gerçek zamanlı senaryolar: Bildiğimiz gibi bir Hizmet API'sini çağırmak bir uygulamada kapsamlı bir işlemdir. Çoğu zaman alan işlem, hizmet API'sını çağırmak için Hizmet istemcisini oluşturmaktır. Service proxy'yi Singleton olarak oluşturursanız, uygulamanızın performansını artıracaktır.

Cepheler: Uygulamanın performansını artırabilecek olan Veritabanı bağlantılarını Singleton olarak da oluşturabilirsiniz.

Günlükler: Bir uygulamada, bir dosyada G / Ç işlemi gerçekleştirmek pahalı bir işlemdir. Logger'ı Singleton olarak oluşturursanız, G / Ç işleminin performansını artıracaktır.

Veri paylaşımı: Sabit değerleriniz veya yapılandırma değerleriniz varsa, bu değerleri uygulamanın diğer bileşenleri tarafından okunabilmesi için Singleton'da tutabilirsiniz.

Önbellekleme: Bildiğimiz gibi bir veritabanından veri almak zaman alan bir işlemdir. Uygulamanızda, DB çağrılarını önleyecek ana ve yapılandırmayı bellekte önbelleğe alabilirsiniz. Bu gibi durumlarda, Singleton sınıfı, ipliğin senkronizasyonu ile önbelleğe almayı, uygulamanın performansını önemli ölçüde artıran verimli bir şekilde işlemek için kullanılabilir.

C # 'da Singleton Tasarım Deseninin Dezavantajları C #' da Singleton Tasarım Desenini kullanmanın dezavantajları aşağıdaki gibidir:

Birim testi çok zordur çünkü bir uygulamaya küresel bir durum kazandırır. Çok iş parçacıklı bir ortamda singleton örneğine erişmek için kilitleme kullanarak nesneyi serileştirmeniz gerektiğinden, bir programdaki paralellik potansiyelini azaltır.

Bunu bir sonraki makaleden aldım.

https://dotnettutorials.net/lesson/singleton-design-pattern/


0

Kilit kullanmadan ve tembel örnekleme olmadan Güvenli Singleton'a iplik geçirin.

Bu uygulamanın statik bir yapıcısı vardır, bu nedenle her Uygulama Etki Alanı için yalnızca bir kez yürütülür.

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

    public static Singleton Instance { get; } = new Singleton();

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.