[英]Instance members of singleton object or static members of class
我正在编写一个侦听器类,该类在随机未使用的端口上创建一个HttpListener并在其上侦听。 我试图使其单身。 但是,我发现在侦听随机HTTP端口失败10次时,很难将该单例对象保持为null
。
(我已将端口号和HttpListener实例显示为单例实例的成员。但是,为简单起见,还有许多其他成员未显示。)这是我的代码:
class Listener
{
private static Listener listener = null; //singleton instance
//member variables
private HttpListener httpListener = null;
private int port = -1;
static Listener()
{
listener = new Listener();
}
private Listener()
{
try
{
port = //randomly generate
httpListener = new HttpListener();
//start listening
}
catch(Exception ex)
{
//cant listen on randomly chosen port
listener = null;
httpListener = null;
port = -1;
return;
}
}
}
但是,在catch()
内部, listener = null
会将listener
设置为null一段时间。 当默认构造函数返回时,它将返回Listener
的新实例,因此静态构造函数内部的listener
始终会为其分配实例。 因此,代替默认构造函数中的listener = null
它应该是this = null
,这是无效的。
因此,我将整个代码移到了静态构造函数中。 但这迫使我
port
和httpListener
) static
或 或在各处使用listener.port
, listener.httpListener
类Listener {private static Listener listener = null; //单个实例
//member variables private HttpListener httpListener = null; private int port = -1; static Listener() { listener = new Listener(); try { listener.port = //randomly generate listener.httpListener = new HttpListener(); //start listening } catch(Exception ex) { //cant listen on randomly chosen port listener = null; return; } } private Listener() { }
}
我不明白
Q1是否使port
和httpListener
static
? (我觉得这有点违反OOP原则)或
Q2是否保留它们作为实例成员并使用listener.
到处? (这是有问题的,因为在我的实际代码中有很多这样的成员和方法,并且我必须在每个地方附加listener.
)
还是我认为这都是错误的,应该采取不同的方法?
直接的问题是,一旦失败,实例构造函数会将静态成员侦听器设置为null。 但是,控制权然后返回到静态构造函数,后者将静态成员侦听器设置为在实例构造函数中创建的对象。 因此,您所看到的行为。
我认为您的(实例)构造函数试图做太多事情。 我会将“开始侦听”逻辑移到单独的方法中,然后从实例构造函数以外的任何地方调用它。 这将使您的错误处理更加容易,例如
class Listener
{
public static Listener listener = null; //singleton instance
//member variables
private HttpListener httpListener = null;
private int port = -1;
static Listener GetListener()
{
if (listener != null)
{
return listener;
}
try
{
listener = new Listener();
listener.StartListening();
return listener;
}
catch (Exception)
{
//cant listen on randomly chosen port
listener.Cleanup();
listener = null;
throw;
}
}
private Listener()
{
port = RandomlyGenerate();
httpListener = new HttpListener();
}
private void StartListening()
{
//start listening
}
private void Cleanup()
{
httpListener.Close();
httpListener = null;
port = -1;
}
}
正如BartoszKP在评论中提到的那样,在此处使用工厂模式可能会更好。
如果您对事件有一个通用的位置感兴趣, 可以将该事件放置在factory类中,或者在Listener类中实现一个静态事件。
public class ListenerFactory {
public IListener CreateListener(URI uri, int port) {
Listener l = new Listener();
l.MessageReceived += OnMessageReceived;
// do whatever with l. loop until connection, or use l.Start() for instance
return l;
}
public static event EventHandler<MessageEventArgs> ListenerMessageReceived;
private static void OnMessageReceived(object sender, MessageEventArgs e) {
// trigger ListenerMessageReceived
}
}
public interface IListener {
event EventHandler<MessageEventArgs> MessageReceived;
void Send(byte[] data);
}
public class Listener : IListener {
// implement interface
}
然后,您只需调用new ListenerFactory().Create(host, port);
当您需要新的侦听器时,并且如果您想侦听所有消息,则可以订阅ListenerFactory.MessageReceived
接收传入消息。
使用此模式,您可以一次创建多个连接,而不必依赖一个类来处理所有连接。
您应该将httpListener的初始化代码移至其自己的方法,以避免重新创建侦听器。 通过这样做,并添加用于获取侦听器实例的属性,如果静态构造函数无法连接,则类可以使用Listener.Instance.Start()
重新连接。
public class Listener
{
private static Listener listener = null; //singleton instance
//member variables
private HttpListener httpListener = null;
private int port = -1;
static Listener()
{
listener = new Listener();
// start listener
try {
listener.Start();
}
catch { }
}
// Use this method in other classes to start listener if it fails
// in static constructor
public static Listener Instance { get { return listener; } }
private Listener()
{
}
public bool IsConnected {
get { return httpListener != null; }
}
public void Start()
{
if (IsConnected) { return; }
try
{
port = //randomly generate
httpListener = new HttpListener();
//start listening
}
catch(Exception ex)
{
//cant listen on randomly chosen port
httpListener = null;
port = -1;
return;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.