【问题标题】:c# singleton class working well confirmationc#单例类工作良好确认
【发布时间】:2020-12-13 01:52:51
【问题描述】:

我需要确认单例模式。

我有一个单例类,我将它用作 dll。我编写了一个引用这个 dll 的程序,并调用了我的单例类。 我写了第二个程序,我也这样做。

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

我试图增加一个静态变量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; } }
    }
    }

方案一:

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

方案二:

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

【问题讨论】:

  • InstanceNumber 存储在内存中。 ““简单”内存(例如在您的示例中)是每个进程。两个进程 => 此数据的两个副本。单例类在这里无关紧要。如果您想要一个真正的跨进程单例,那么您必须使用共享的内存跨进程,例如:stackoverflow.com/questions/7894224/…

标签: c# singleton call singleton-type


【解决方案1】:

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

没有。这不是它的工作原理。您的每个程序都会在其内存空间中加载 dll 的副本,因此您的每个程序都有自己的类实例。你可以开始你的第一个程序 5 次,你的第二个程序 3 次,你的班级将有 8 个实例。

它们不会被共享。

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

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

【讨论】:

  • 我明白,但目标是在程序之间共享方法而不是数据。我只想要一种从我的 PLC 询问数据的方法,这样我就不会在方法上重叠。如果我想向 PLC 询问某个变量的值,我不希望其他人尝试从同一个 PLC 询问另一件事。
  • 所以我认为,就我的目的而言,最好启动一个只处理 PLC 的应用程序。
  • 我不确定 PLC 是什么,但您不需要单例来共享方法。你可以只拥有一个带有静态方法的静态类。
  • @JudgeDreed 所以我也不确定 PLC 是什么,但 Google 说它是硬件。你的 cmets 听起来你混合了 locksingleton。如果我错了纠正我。您需要两个应用程序都可以等待的单个锁,并允许一个应用程序进入锁。例如,一个名为Semaphore
  • @JudgeDreed 单例通常是指一种设计模式,在 one 应用程序域中,该类型只能存在一个实例。如果将单例加载到两个应用程序中,您将有两个实例,每个应用程序中都有一个。即使这些进程间实例属于同一类型并且来自同一个 DLL,它们也不认识其他进程。如果您希望您的两个应用程序可以相互交谈并协商谁可以做什么 atm,那么单例不是答案。您将需要一个 lock,它存在于两个应用程序都知道如何使用的操作系统级别。
【解决方案2】:

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

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

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

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

如果您想在多个进程之间共享一个全局系统单例,您需要使用 COM/DCOM 等一些 client-server 技术来实现 server 在晚年。

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

您可以使用许多技术,例如 Windows 服务、命名管道、TCP/Sockets、Remoting、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)

【讨论】:

    【解决方案3】:

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

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

    1. 跨域单例(使用共享内存)。您可以找到详细信息here
      Simon Mourier还在cmets中分享了一个不错的链接:点击here关注。

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

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

    【讨论】:

      【解决方案4】:

      如果我告诉你即使我有两个他们调用的程序,我是对的吗 都是我的单例类的单个实例?

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

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

      当您使用 C# 时,我建议您查看这个库 (https://github.com/OPCFoundation/UA-.NETStandard),它是根据 OPC Foundation 标准使用 .NET Framework 实现的 OPC UA 堆栈实现。

      【讨论】:

        【解决方案5】:

        正如其他答案所暗示的,单例实例不在两个程序之间共享。每个程序都在自己的操作系统进程中运行,并拥有自己的 DLL 副本

        【讨论】:

          【解决方案6】:

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

          在您的示例中,如果两个程序同时运行,那么第二个运行应该返回 2,因为第一个获取 Singleton 的程序会将变量增加到一个。

          【讨论】:

          • 否,因为在您看来,第二个 dll 不会被实例化,因为已经完成了一个。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-29
          • 2010-09-05
          • 2014-04-29
          • 2016-04-29
          相关资源
          最近更新 更多