Шаблон Singleton в .Net не возможен? - PullRequest
3 голосов
/ 22 сентября 2009

У меня очень интересная ситуация, я выяснил, что синглтон-паттерн не все возможен с .net framework (любая версия)

посмотрите на этот код ниже

namespace SingletonPattern
{
    class Singleton
    {
    private static readonly Singleton instance = new Singleton();
    private static int mcount = 0;

    private Singleton() {

        mcount += 1;
        Console.WriteLine("Creating {0} instances of Singleton Class", mcount.ToString());
    }

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

class program
{
    static void Main()
    {
        for (int i = 0; i < 1000; i++)
        {
            System.Activator.CreateInstance(Type.GetType("SingletonPattern.Singleton"), true);
        }

        Console.ReadLine();


        }
    }
}

с помощью System.activator любой собеседник может разорвать синглтон-паттерн.

так, кто в опасности?

любой парень, который написал какой-то компонент лицензирования, в котором лицензия реализована как шаблон синглтона.

Любой серверный код, использующий шаблон Singleton.

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

Ответы [ 9 ]

28 голосов
/ 22 сентября 2009

То, что таким способом можно сознательно обойти шаблон, не означает, что сам шаблон " невозможен ".

13 голосов
/ 22 сентября 2009

Это правда, что эта реализация синглтона неверна, но это не значит, что кто-то не может создать лучшую реализацию синглтона.

11 голосов
/ 22 сентября 2009

Точно так же все частные методы не являются частными, потому что вы можете получить к ним доступ, используя отражение.

Я не вижу проблем с этим.

7 голосов
/ 22 сентября 2009

Чтобы использовать System.Activator.CreateInstance, вам нужны высокие разрешения. Конечно, если вам разрешено игнорировать модификаторы доступа, потому что система доверяет вам, вы можете нарушить код, который зависит от потребителей, уважающих модификаторы доступа.

Обычно код обычно не имеет этих разрешений.

4 голосов
/ 22 сентября 2009

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

2 голосов
/ 22 сентября 2009

Любая схема лицензирования на стороне клиента может быть нарушена.

Вы можете обойти это, создав исключение, если счетчик больше 1 - но, опять же, другой код может использовать Reflection для сброса счетчика. Вызывающий код может даже изменить вашу сборку перед загрузкой, полностью удалив лицензионный код!

Никакой язык программирования, обфускатор и т. Д. Не может полностью защитить вас от этого - если бы это было возможно, наверняка издатели игр уже использовали бы его для создания нерушимой защиты от копирования!

Как только вы получите недоверенный код в той же «зоне безопасности», что и ваш код; ты уже проиграл.

2 голосов
/ 22 сентября 2009

, если вы хотите защитить от этого крайнего случая, просто измените частный ctor:

private Singleton() { throw new ApplicationException{
     "Don't call System.Activator.CreateInstance on this class"); }

И тогда вам нужно будет добавить еще один параметризованный частный ctor для фактического создания синглтона ... возможно, с секретным параметром, который будет передавать только инициализатор ... весь класс будет:

class Singleton
{    
   private static readonly Singleton inst = new Singleton("MySecretWord");    
   private static int mcount = 0;   
   private Singleton(string secret)
   { if (secret != "MySecretWord")  
       throw new ApplicationException{
           "Don't call Private constructor on this class"); 
   }
   private Singleton() { throw new ApplicationException{
     "Don't call System.Activator.CreateInstance on this class"); }
  public static Singleton Instance { get  {  return inst ;  } }
}

Но зачем идти на все эти неприятности? если кто-то захочет разобраться с вашим одноэлементным шаблоном с помощью CreateInstance, тогда в этом проблема, нет?

0 голосов
/ 07 ноября 2012

Проверьте трассировку стека в вашем частном конструкторе, чтобы убедиться, что он вызывается только из класса Singleton, а не из других источников.

using System;
using System.Diagnostics;

class Program
{
    public static void Main(string[] args)
    {
        //This should work and not throw any exception
        Singleton singleton = Singleton.Instance;
        Debug.Assert(singleton != null);

        //This should throw an exception
        Singleton s = (Singleton)Activator.CreateInstance(typeof(Singleton), true);
    }
}

public class Singleton
{
    private static Singleton uniqueInstance = new Singleton();

    private Singleton() 
    {
        StackTrace trace = new StackTrace();
        StackFrame frame = trace.GetFrame(1);

        //Check that the private constructor is only getting invoked by the static initializer, otherwise throw exception
        if (String.Compare(trace.GetFrame(1).GetMethod().Name, ".cctor") != 0)
            throw new InvalidOperationException(
                "Don't call Private constructor on this class. Abide by Singleton semantics.");
    }

    public static Singleton Instance { get { return uniqueInstance; } }
}
0 голосов
/ 22 сентября 2009

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

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

Но - с блокировочным механизмом вы получите удар по производительности, поэтому вы должны взвесить все преимущества.

...