.net C#单例类工作良好确认

fzwojiic  于 11个月前  发布在  .NET
关注(0)|答案(6)|浏览(93)

我需要确认一下单例模式。
我有一个单例类,我用它作为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; } }
    }
    }

字符串
程序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);
    }
}
}


方案二:

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


的数据

tcomlyy6

tcomlyy61#

如果我告诉你,即使我有两个程序,它们也调用我的单例类的一个示例,对吗?
不不是这样的你的每一个程序都在它们的内存空间中加载一个dll的副本,所以你的每一个程序都有它自己的类的示例。你可以启动你的第一个程序5次,第二个程序3次,你的类将有8个示例。
他们不会被分享。
如果你需要证明,只要让它可以 * 写 * 到示例,例如 * 设置 * 名称。您将看到,无论您在一个程序中做什么,其他程序都不会看到这些更改。
在应用程序之间共享数据有不同的方法,共享dll中的类不是其中之一,因为每个程序加载它自己的dll副本。

ifmq2ha2

ifmq2ha22#

在一个程序中的代码是永远不会重复的,否则你重复自己,但在运行时没有重复:一个方法是不重复的,有一个方法,总是有一个方法。代码是相同的,永远不会改变,否则使用一些先进的技术所使用的代码保护或病毒例如。因此,处理器和操作系统只掌握一个运行代码的示例,一旦加载到内存中,在 CODE SEGMENT 中,并且直到最后才改变。
这是 DATA SEGMENT 中的数据,您使用类型、局部变量、示例变量成员、静态成员和类、单例模式等不同的分配方式来管理这些数据。
也就是说,每次可执行文件加载一个DLL时,它都会加载它的一个副本,因此如果5个应用程序加载一个DLL,则内存中有5个DLL副本,因此这里有5个单例示例,但每个应用程序都是唯一的。因此,这里的单例存在于您启动的每个进程示例中:每个应用程序有一个单例,每个加载的DLL有一个单例。因此,您总是看到1InstanceNumber:每个应用程序一个,但是1 + 1 + 1 +...=很多,数据不共享。
因此,如果在每个运行的应用程序中为myName设置不同的值,则每个应用程序都同时具有自己的更改值,因为它既不共享也不复制。
如果你想让一个全局系统单例在多个进程之间共享,你需要使用一些客户端-服务器技术实现一个服务器,比如旧时代的 COM/DCOM
要做到这一点,你不需要使用一个由多个应用程序加载的DLL来将单例放入其中,但你必须有一个真实的的应用程序(当然可以加载一些DLL,但只有这个服务器加载它们,并且单例代码可以放在DLL中,我希望在这里说这不会让你感到困惑),其他应用程序连接并要求使用提供的公共服务。
您可以使用许多技术,如Windows服务,命名管道,TCP/套接字,远程处理,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://learn.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)

yyhrrdl8

yyhrrdl83#

在其他答案中提到了很多技术,我建议您考虑找到最适合您需求的技术。从本质上讲,所有的答案都告诉你(正确地),你不能仅仅通过共享一个dll来建立一个单例。
另外三种方法还没有提到(我假设您不仅需要在客户端之间共享应用程序名称,还希望共享更多数据-如果您更准确地告诉我们您的用例,我们可以更好地帮助您找到解决问题的方案):
1.跨域单例(使用共享内存)。您可以找到详细信息here
Simon Mourier也在评论中分享了一个很好的链接:单击here跟随它。
1.缓存。用于存储简单的数据结构。你可以使用像Redis(https://redis.io/)这样的缓存来在你的客户端之间共享数据。它安装简单,使用简单(你甚至可以在docker示例中运行它),它使用键值集合来存储共享数据。
1.建立数据库。然后,两个客户端都连接到数据库,并将共享信息存储在那里。甚至可以存储复杂的数据结构。
可以在这里找到如何在C#中访问数据库的完整演练:https://www.guru99.com/c-sharp-access-database.html此描述适用于SQL Server,但当然它也适用于其他数据库(如PostgreSQL,MySQL等)-如果您使用不同的数据库系统,则需要特定的数据库库库,您可以通过NUGET轻松找到。

cmssoen2

cmssoen24#

如果我告诉你,即使我有两个程序,它们也调用我的单例类的一个示例,对吗?
简短回答:每个程序都有自己的示例。
然而,在你写的一条评论中,你的目标是从PLC检索数据,并确保这只做一次。这正是SCADA服务器所做的。我建议你看看什么是OPC服务器,以及如何使用不同的数据传输(OLE,TCP等)。
当你使用C#时,我建议你看看这个库(https://github.com/OPCFoundation/UA-.NETStandard),它是一个根据OPC基金会标准使用.NET框架的OPC UA堆栈实现。

mbyulnm0

mbyulnm05#

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

voj3qocg

voj3qocg6#

这有点让人困惑。您希望在两个不同的程序之间使用Singleton作为DLL,但每个程序在加载时将加载DLL的不同示例。所以他们不会使用同一个Singleton。
在你的例子中,如果两个程序同时运行,那么第二个运行的程序应该返回2,因为第一个获得Singleton的程序会将变量递增为1。

相关问题