С# одноэлементный класс работает хорошо, подтверждение

Мне нужно подтверждение об одноэлементном шаблоне.

У меня есть одноэлементный класс, и я использую его как dll. Я пишу программу со ссылкой на эту dll и вызываю свой класс singleton. Я пишу вторую программу и делаю то же самое.

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

Я попытался увеличить статическую переменную instancenumber, которая увеличивается каждый раз, когда я передаю конструктор, и обе программы сообщают мне, что instancenumber равен 1. Так что все должно быть в порядке, но мне нужен ваш совет, чтобы быть уверенным.

Спасибо. с уважением

Класс Синглтон:

namespace SingletonClassLib
{
    public class SingletonClass
    {
        public static int InstanceNumber = 0;
        private static string myName;
        #region //Singleton initialisation
        private SingletonClass() { createInstance(); }
        private void createInstance()
        {
            InstanceNumber++;
            myName = myName + InstanceNumber.ToString();
        }
        public static SingletonClass _I { get { return NTCSession._i; } }
        private class NTCSession
        {
            static NTCSession() { }
            internal static readonly SingletonClass _i = new   SingletonClass();
        }
        private static List<WeakReference> instances = new List<WeakReference>();
        #endregion //Singleton initialisation
        public static string askname { get { return myName; } }
    }
    }

Программа 1:

using System.Windows.Forms;
using SingletonClassLib;

namespace Singletontest
{

public partial class Form1 : Form
{
    SingletonClass myclass = SingletonClass._I;
    public Form1()
    {
        InitializeComponent();
        string Name = SingletonClass.askname;
        MessageBox.Show("Program first: "+Name);
    }
}
}

Программа 2:

using System.Windows.Forms;
using SingletonClassLib;

namespace Singletontest
{

public partial class Form1 : Form
{
    SingletonClass myclass = SingletonClass._I;
    public Form1()
    {
        InitializeComponent();
        string Name = SingletonClass.askname;
        MessageBox.Show("Program second: "+Name);
    }
}
}

Результат программ


person JudgeDreed    schedule 24.08.2020    source источник
comment
InstanceNumber хранится в памяти. Простая память (например, в вашем образце) предназначена для каждого процесса. Два процесса =› две копии этих данных. Класс singleton здесь не имеет значения. Если вам нужен настоящий кросс-процессный синглтон, вы должны использовать память, разделяемую между процессами, например: stackoverflow.com/questions/7894224/   -  person Simon Mourier    schedule 18.09.2020


Ответы (6)


Как показывают другие ответы, экземпляр singleton не используется двумя программами. Каждая программа работает в своем собственном процессе ОС, который имеет собственную копию DLL.

person Krusty    schedule 22.09.2020

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

Нет. Это не так. Каждая из ваших программ загружает копию dll в свое пространство памяти, поэтому каждая из ваших программ имеет свой собственный экземпляр класса. Вы можете запустить свою первую программу 5 раз, а вторую программу 3 раза, и будет 8 экземпляров вашего класса.

Они не делятся.

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

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

person nvoigt    schedule 17.09.2020
comment
Я понимаю, но цель состоит в том, чтобы обмениваться между программами методами, а не данными. Мне нужен только один метод для запроса данных из моего ПЛК, чтобы у меня не было дублирования методов. Если я хочу запросить у ПЛК значение определенной переменной, я не хочу, чтобы кто-то еще пытался запросить что-то еще у того же ПЛК. - person JudgeDreed; 17.09.2020
comment
Поэтому я думаю, что для моей цели было бы лучше запустить приложение, которое будет иметь дело с ПЛК и ничем другим. - person JudgeDreed; 17.09.2020
comment
Я не уверен, что такое ПЛК, но вам не нужен синглтон для обмена методами. Вы могли бы просто иметь статический класс со статическими методами. - person nvoigt; 17.09.2020
comment
@JudgeDreed Так что я тоже не уверен, что такое ПЛК, но Google говорит, что это аппаратная вещь. Мне кажется, что ваши комментарии смешали lock и singleton. Поправьте меня если я ошибаюсь. Вам нужна единая блокировка, которую могут ожидать оба приложения, и позволять одному приложению входить в блокировку. Как, например, именованный семафор . - person weichch; 17.09.2020
comment
@JudgeDreed Синглтон обычно относится к шаблону проектирования, который в одном домене приложения может существовать только один экземпляр типа. Если вы загрузите синглтон в два приложения, у вас будет два экземпляра, по одному в каждом приложении. И ни один из этих межпроцессных экземпляров не знает других, даже если они одного типа и из одной DLL. Если вы хотите, чтобы ваши два приложения могли общаться друг с другом и договариваться о том, кто и что может делать, синглтон не является ответом. Вам понадобится блокировка, существующая на уровне ОС, которую оба приложения знают, как использовать. - person weichch; 17.09.2020

В программе код никогда не повторяется, иначе что бы вы ни повторялись, но нет дублирования во время выполнения: метод не дублируется, а имея один метод, всегда есть один метод. Код тот же и никогда не меняется, в противном случае используются некоторые передовые методы, используемые, например, защитой кода или вирусами. Таким образом, процессор и операционная система управляют только одним экземпляром исполняемого кода, однажды загруженного в память, в СЕГМЕНТЕ КОДА, и он никогда не изменяется до конца.

Это данные в СЕГМЕНТЕ ДАННЫХ, с которыми вы работаете и которыми вы управляете различными способами распределения, используя типы, локальные переменные, члены переменных экземпляра, статические члены и классы, шаблон singleton и т. д. это изменение.

Тем не менее, каждый раз, когда исполняемый файл загружает DLL, он загружает ее копию, поэтому, если 5 приложений загружают одну DLL, в памяти будет 5 копий DLL, поэтому здесь есть 5 экземпляров синглетонов, которые, однако, уникальны для каждого. заявление. Следовательно, синглтон здесь существует в каждом экземпляре запускаемых вами процессов: у вас есть один синглтон на приложение, один на загруженную DLL. Следовательно, вы всегда видите 1 вместо InstanceNumber: по одному в каждом приложении, но 1 + 1 + 1 + ... = много, и данные не используются совместно.

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

Если вы хотите, чтобы глобальный системный синглтон был общим для нескольких процессов, вам необходимо реализовать сервер с использованием некоторых технологий клиент-сервер, таких как COM/DCOM в старости.

Для этого вы не используете DLL, загруженную несколькими приложениями, чтобы поместить в нее синглтон, но у вас должно быть реальное приложение (которое, конечно, может загрузить некоторые DLL, но только этот сервер загружает их, и код синглтона может быть помещен в DLL, и я надеюсь, что это не смутит вас здесь), когда другие приложения подключаются и просят использовать предоставляемые общедоступные услуги.

Вы можете использовать множество технологий, таких как служба Windows, именованные каналы, TCP/сокеты, удаленное взаимодействие, WFC, веб-службы и т. д.

Вы окончательно поймете, когда я скажу, что база данных подобна использованию синглтона, о котором вы просите: база данных — это один и только один экземпляр (в общем), и клиенты подключаются к ней и используют, читают и пишут, создают и изменяют и удалить одно и то же местоположение данных, совместно используемое несколькими локальными и/или удаленными приложениями.

Конечно, у вас есть, например, плохой пример для демонстрации, и это сделано специально, SQLite, который может использоваться как DLL, загружаемый каждым клиентом, но эта DLL управляет одним файлом базы данных. Так что имейте в виду, что вы хотите управлять одними и теми же данными, и эта DLL делает это, потому что данные находятся не в памяти, а только в одном файле.

Таким образом, для решения вашей проблемы вам необходимо:

  • Создайте код синглтона.

  • Выберите серверную технику, адаптированную к вашим потребностям.

  • Поместите синглтон в исполняемый файл или в dll, загружаемый только исполняемым файлом сервера.

  • Создайте клиентский код.

  • Запустите одноэлементное приложение.

  • Запустите клиент или клиенты.

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

При необходимости вы должны запретить запуск серверного процесса несколько раз, используя GUID сборки в качестве имени мьютекса, чтобы обеспечить строгое соответствие:

Ограничение нескольких экземпляров приложения

Как ограничить приложение только к одному экземпляру

Следовательно, у вас будет два проекта в обозревателе решений Visual Studio. Visual Studio предлагает способы отладки, запуская несколько проектов одновременно:

https://docs.microsoft.com/visualstudio/ide/how-to-set-multiple-startup-projects

Вот несколько статей:

Создание службы Windows на C# (C-SharpCorner)

Разработка и установить службу Windows на C# (C-SharpCorner)

Сравнение WCF с веб-службами и .NET Удаленное взаимодействие (CodeProject)

Взаимодействие между процессами (C# Vault)

Полнодуплексное асинхронное чтение/запись с именованным Трубы (CodeProject)

Программирование сокетов на C# (C-SharpCorner)

Программирование сокетов на C# (GeeksForGeeks)

Простое взаимодействие клиент-сервер с использованием C# (CodeProject)

person Olivier Rogier    schedule 19.09.2020

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

Еще не были упомянуты три дополнительных подхода (я предполагаю, что вам не просто нужно поделиться именем приложения между клиентами, вы хотите поделиться большим количеством данных - если вы сообщите нам более точно свой вариант использования, мы сможем помочь вам лучше найти решение вашего вопроса):

  1. Междоменный синглтон (с использованием общей памяти). Подробности можно найти здесь.
    Саймон Мурье также поделился хорошей ссылкой в ​​комментариях: Нажмите здесь, чтобы следовать ему.

  2. Кэширование. Полезно для хранения простой структуры данных. Вы можете использовать кеш, например Redis (https://redis.io/), для обмена данными между вашими клиентами. Его просто установить, просто использовать (вы даже можете запустить его в экземпляре докера), и он использует коллекцию ключей и значений для хранения общих данных.

  3. Настройте базу данных. Затем оба клиента подключаются к базе данных, и вы сохраняете там общую информацию. Можно сохранять даже сложные структуры данных.
    Полное пошаговое руководство по доступу к базе данных на C# можно найти здесь: https://www.guru99.com/c-sharp-access-database.html Это описание для SQL Server, но, конечно, оно работает аналогично для других баз данных ( такие как PostgresSQL, MySQL,...) - если вы используете другую систему баз данных, вам нужны определенные библиотеки баз данных, которые вы можете легко найти через NUGET.

person Matt    schedule 21.09.2020

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

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

Однако в одном из комментариев вы написали, что ваша цель — получить данные с ПЛК и убедиться, что это делается только один раз. Это именно то, что делает сервер SCADA. Я предлагаю вам взглянуть на то, что такое OPC-сервер и как его можно использовать с различной передачей данных (OLE, TCP и т. д.).

Поскольку вы используете C#, я предлагаю вам взглянуть на эту библиотеку (https://github.com/OPCFoundation/UA-.NETStandard), который представляет собой реализацию стека OPC UA с использованием .NET Framework в соответствии со стандартом OPC Foundation.

person Jamaslab    schedule 24.09.2020

Это немного сбивает с толку. Вы хотите использовать Singleton между двумя разными программами в качестве DLL, но каждая программа при загрузке будет загружать другой экземпляр DLL. Таким образом, они не будут использовать один и тот же синглтон.

В вашем примере, если две программы запускаются одновременно, то одна запущенная секунда должна возвращать 2, поскольку первая программа, получившая Singleton, будет увеличивать переменную до единицы.

person Nick M.    schedule 17.09.2020
comment
Нет, потому что, с вашей точки зрения, вторая dll не будет создана, поскольку одна уже сделана. - person JudgeDreed; 17.09.2020