c# singleton class 运行良好确认

c# singleton class working well confirmation

我需要确认单例模式。

我有一个单例 class,我将其用作 dll。我编写了一个引用此 dll 的程序,并将我的单身人士称为 class。 我写了第二个程序,我也这样做。

如果我告诉你,即使我有两个程序,它们都调用我的单例实例,我说得对吗 class?

我试图增加一个静态变量 instancenumber,每次我通过构造函数时它都会递增,两个程序都告诉我 instancenumber 是 1。所以应该没问题,但我需要你的建议才能确定。

谢谢。最好的问候

Class单例:

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);
    }
}
}

这有点令人困惑。你想在两个不同的程序之间使用一个 Singleton 作为 DLL,但是每个程序在加载时都会加载 DLL 的不同实例。因此,他们不会使用相同的 Singleton。

在您的示例中,如果两个程序同时 运行,那么第二个 运行 应该 return 2 因为第一个获得 Singleton 的程序会递增可变为一。

Am I right if I tell you that even if I have two program they call both a single instance of my singleton class?

没有。这不是它的工作原理。您的每个程序都会在其内存中加载 dll 的副本 space,因此您的每个程序都有自己的 class 实例。您可以启动您的第一个程序 5 次,您的第二个程序 3 次,并且您的 class.

将有 8 个实例

它们不会被分享。

如果需要证明,只需要证明就可以写入到实例中,例如设置名称。您会发现,无论您在一个程序中做什么,其他程序都不会看到这些变化。

在应用程序之间共享数据有多种方式,共享 dll 中的 class 不是其中之一,因为每个程序加载它自己的 dll 副本。

在一个程序中,代码永远不会重复,否则你自己重复什么,但在运行时没有重复:一个方法是不重复的,有一个方法,总是有一个方法。代码是相同的,永远不会改变,否则使用代码保护或病毒使用的一些高级技术。所以处理器和操作系统只掌握 运行 代码的一个实例,一旦加载到内存中,在 CODE SEGMENT 中,并且直到最后才改变。

这是 DATA SEGMENT 中的数据,包含您的工作以及您使用类型、局部变量、实例变量成员、静态成员和 类, 单例模式等等,那个变化。

就是说,每次可执行文件加载一个 DLL 时,它都会加载它的一个副本,所以如果 5 个应用程序加载一个 DLL,内存中就有 5 个 DLL 副本,所以这里有 5 个单例实例然而,每个应用程序都是唯一的。因此,这里的单例存在于您启动的每个进程实例中:每个应用程序都有一个单例,每个加载的 DLL 都有一个单例。因此,您总是会看到 1 for InstanceNumber:每个应用程序中有一个,但是 1 + 1 + 1 + ... = 很多并且数据不共享。

因此,如果您在每个 运行 应用程序中将 myName 设置为不同的值,则每个应用程序同时都有自己的更改值,因为它既不共享也不复制。

如果你想在多个进程之间共享一个全局系统单例,你需要使用一些client-server[=100来实现一个服务器 =] 老年代COM/DCOM等技术

要做到这一点,您不会使用由多个应用程序加载的 DLL 将单例放入其中,但您必须有一个真实的应用程序(当然可以加载一些 DLL,但只有该服务器加载它们和单例代码可以放在 DLL 中,我希望在这里这样说不会让您感到困惑),其他应用程序连接并要求使用提供的 public 服务。

您可以使用许多技术,例如 Windows 服务、命名管道、TCP/Sockets、远程处理、WFC、Web 服务等。

当我说数据库就像您要求的单例用法时,您将最终理解:数据库是一个且只有一个实例(通常),客户端连接到它并使用、读取和写入、创建、更改和删除在本地和/或远程多个应用程序之间共享的相同数据位置。

当然,例如,这里有一个不好的示例用于演示,它是故意完成的,SQLite 可以用作每个客户端加载的 DLL,但是这个 DLL 管理单个数据库文件。所以请记住,你想要做的是管理相同的数据,而这个 DLL 这样做是因为数据不在内存中,而只在一个文件中。

因此,要解决您的问题,您需要:

  • 创建单例代码。

  • 选择适合您需求的服务器技术。

  • 将单例放入可执行文件或仅由服务器可执行文件加载的 dll 中。

  • 创建客户端代码。

  • 运行单例应用。

  • 运行客户或客户。

有些技术允许客户端在尚未启动的情况下直接启动服务器。

如果需要,您必须禁止 运行 服务器进程多次使用程序集 GUID 作为互斥锁的名称以保持高度一致:

Restrict multiple instances of an application

How to Restrict the Application to Just One Instance

因此,您的 Visual Studio 解决方案资源管理器中将有两个项目。 Visual Studio 提供了通过 运行 多个项目同时进行调试的方法:

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

这里有一些文章:

Create A Windows Service In C# (C-SharpCorner)

Develop and Install a Windows Service in C# (C-SharpCorner)

WCF Comparison with Web Services and .NET Remoting (CodeProject)

Inter Process Communication (C# Vault)

Full Duplex Asynchronous Read/Write with Named Pipes (CodeProject)

Socket Programming In C# (C-SharpCorner)

Socket Programming in C# (GeeksForGeeks)

Simple Client-server Interactions using C# (CodeProject)

其他答案中提到了很多技术,我建议您考虑找到最符合您需求的技术。本质上,所有的答案都(正确地)告诉你,你不能仅仅通过共享一个 dll 来建立单例。

尚未提及另外三种方法(我假设您不仅需要在客户端之间共享应用程序名称,还想共享更多数据 - 如果您更准确地告诉我们您的用例,我们可以帮助您更好地找到问题的解决方案):

  1. Cross-domain 单例(使用共享内存)。您可以找到详细信息 here.
    Simon Mourier has also shared a good link in the comments: Click here 以关注它。

  2. 缓存。用于存储简单的数据结构。您可以使用像 Redis (https://redis.io/) 这样的缓存在客户端之间共享数据。它安装简单,使用简单(您甚至可以在 docker 实例中 运行 它)并且它使用 key-value 集合来存储共享数据。

  3. 设置数据库。然后两个客户端都连接到数据库,您将共享信息存储在那里。甚至可以存储复杂的数据结构。
    可以在此处找到如何使用 C# 访问数据库的完整演练: https://www.guru99.com/c-sharp-access-database.html 此描述适用于 SQL 服务器,但当然它也适用于其他数据库(例如 PostgresSQL、MySQL、...)——如果您使用的是不同的数据库系统,您需要特定的数据库库,您可以通过 NUGET 轻松找到这些库。

正如其他答案所暗示的那样,两个程序之间不共享单例实例。每个程序都在自己的 OS 进程中运行,该进程有自己的 DLL 副本

Am I right if I tell you that even if I have two program they call both a single instance of my singleton class?

简答:不,每个程序都有自己的实例。

但是,在您写的一条评论中,您的目标是从 PLC 检索数据并确保只完成一次。这正是 SCADA 服务器所做的。我建议您看一下 OPC 服务器是什么以及它如何用于不同的数据传输(OLE、TCP 等)。

由于您使用的是 C#,我建议您看一下这个库 (https://github.com/OPCFoundation/UA-.NETStandard),它是一个根据 OPC 基金会标准使用 .NET Framework 的 OPC UA 堆栈实现。