我正在编写一个监听器类,它会随机创建一个HttpListener
未使用的端口并监听它。我试着把它变成单身。不过我
在听时很难保持单个对象null
随机HTTP端口失败10次。
(我已将端口号和HttpListener实例显示为singleton的成员 实例。然而,还有许多其他成员我没有展示过 简单。)这是我的代码:
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
无处不在
类侦听器 { 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.
或者我认为这一切都错了,应该遵循不同的方法?
答案 0 :(得分:1)
当前的问题是,在失败时,实例构造函数将静态成员侦听器设置为null。但是,控制然后返回静态构造函数,该构造函数将静态成员侦听器设置为在实例构造函数中创建的对象。因此,你所看到的行为。
我认为你的(实例)构造函数试图做太多。我会将'start listening'逻辑移动到一个单独的方法中,并从实例构造函数以外的任何地方调用它。这将使你的错误处理更容易,例如。
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;
}
}
答案 1 :(得分:0)
正如BartoszKP在评论中提到的那样,你可能会更好地使用工厂模式。
如果您有兴趣为事件提供一个共同的位置,那么可以将该事件放在工厂类中,或者在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;
}
}
}