我在这里遇到了很多问题。我有一个MVP应用程序,我有一个模型来处理与外部设备通信的实现。在应用程序中,我创建了这个类的4个实例。每个实例使用唯一的IP和端口通过UDP套接字与其外部设备进行通信。
现在,对于所有初始测试,一切似乎都很好,因为我有4个视图,每个视图显示每个设备的唯一计数。为了进行测试,我总是只连接到一个设备而其他3个连接什么也没做,但是视图总是按预期显示为零。
当我开始以编程方式创建单个log4net记录器以根据计时器触发记录每个实例的计数时出现问题。我发现每个日志文件记录的计数相同!我认为这是我的log4net实现,但是在调试时我自己在调试器中看到每个实例返回相同的计数。
当创建模型的实例时,它们都被传递给演示者,演示者持有对每个模型的引用。每个模型都有一个唯一的字符串标识符,这是我在调试时查看的实例(除IP和端口外)。
此外,我应该注意,计数是在接收到未经请求的UDP数据包时设置的,该数据包从未在3个实例中出现。
我的内容如下。
HeadModel
-HeadModelAbstract
--SubModel
--- SubModelAbstract
引用的计数位于SubModel中。它是以这种方式完成的,因为我需要一个类来与具有有限功能的设置级别的基本级设备进行通信。但是,更高级的设备将具有该功能和附加功能。我原本想传递接口,但发现这样做会隐藏SubModel中我仍然想要公开的属性和方法,所以我选择了你看到的抽象实现。
感谢所有到目前为止努力帮助的人。
摘要 - 为什么类的4个唯一实例都为相同的非静态属性返回相同的值?
更新:这是misc代码
SystemStatus保存所有计数和状态。 ParseSystemStatus函数是从每次收到UDP消息时触发的事件处理程序调用的。
public class SuccintClass : SuccintAbstract{
UdpServer udpServer = null;
public SuccintClass(int port){
udpServer = new UdpServer(port); //Start receiver on port 3000
udpServer.PacketReceived += client_UnsolicitedMessageReceived;
}
private void client_UnsolicitedMessageReceived(object sender, PacketReceivedEventArgs e) {
ushort msgID = (ushort)((e.Buffer.Data[10]<<8) + e.Buffer.Data[11]);
byte[] data = new byte[e.Buffer.Length];
Array.Copy(e.Buffer.Data, 0, data, 0, e.Buffer.Length);
switch (msgID) {
case 9001:
break;
case 0x5000:
break;
case 9005: //System Status
ParseSystemStatus(data);
OnSystemStatusReceived(new SystemStatusReceivedEventArgs(this.sysStatus));
break;
case 9014:
break;
default:
break;
}
}
private SystemStatus sysStatus = SystemStatus.NullStatus;
public void ParseSystemStatus(byte[] buffer) {
int CounterOffset = 14;
int[] converted = new int[6];
for (int i = 0; i < 6; i++) {
converted[i] = BitConverter.ToInt32(buffer, i * 4 + CounterOffset);
}
this.sysStatus.State = (SystemStatus.SystemState)converted[0];
this.sysStatus.Count1 = converted[1];
this.sysStatus.Count2= converted[2];
this.sysStatus.Count3= converted[3];
this.sysStatus.Count4= converted[4];
this.sysStatus.Count5= converted[5];
}
}
然后UdpServer看起来像这样
sealed class UdpServer : IDisposable {
public UdpServer( int serverPort ) {
this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
this.socket.Bind( new IPEndPoint( IPAddress.Any, serverPort ) );
for ( int i = 0; i < 200; i++ ) {
BeginAsyncReceive( );
}
}
~UdpServer( ) {
Dispose( false );
}
public void Dispose( ) {
Dispose( true );
GC.SuppressFinalize( this );
}
private void Dispose( bool isDisposing ) {
if ( !disposed ) {
disposed = true;
rwLock.AcquireWriterLock( Timeout.Infinite );
socket.Close( );
rwLock.ReleaseWriterLock( );
while ( threads > 0 )
Thread.Sleep( 1 );
}
}
private bool disposed;
private void BeginAsyncReceive( ) {
rwLock.AcquireReaderLock( Timeout.Infinite );
UdpPacketBuffer buffer = UdpPacketBufferPool.GetInstance( ).GetFromPool( );
try {
socket.BeginReceiveFrom( buffer.Data, 0, buffer.Data.Length, SocketFlags.None, ref buffer.RemoteEndPoint, EndAsyncReceive, buffer );
Interlocked.Increment( ref threads );
}
catch ( SocketException exc ) {
if ( logger.IsWarnEnabled ) {
logger.Warn( "Error happened at the start of packet acquisition." );
logger.Warn( exc.ToString( ) );
}
}
catch ( ObjectDisposedException exc ) {
}
rwLock.ReleaseReaderLock( );
}
private void EndAsyncReceive( IAsyncResult asyncResult ) {
BeginAsyncReceive( );
rwLock.AcquireReaderLock( Timeout.Infinite );
UdpPacketBuffer buffer = (UdpPacketBuffer)asyncResult.AsyncState;
try {
buffer.Length = socket.EndReceiveFrom( asyncResult, ref buffer.RemoteEndPoint );
OnPacketReceived( new PacketReceivedEventArgs( buffer ) );
}
catch ( SocketException exc ) {
logger.Warn( "Error happened during completion of packet acquisition." );
logger.Warn( exc.Message );
logger.Warn( exc.StackTrace );
}
catch ( ObjectDisposedException ) {
}
Interlocked.Decrement( ref threads );
rwLock.ReleaseReaderLock( );
}
private void OnPacketReceived( PacketReceivedEventArgs args ) {
EventHandler<PacketReceivedEventArgs> handler = PacketReceived;
if ( handler != null ) {
handler( this, args );
}
}
public event EventHandler<PacketReceivedEventArgs> PacketReceived;
private int threads;
private ReaderWriterLock rwLock = new ReaderWriterLock( );
private Socket socket;
private ILog logger = LogManager.GetLogger( typeof( UdpServer ) );
}
最后,使用访问SystemStatus对象属性的getter和setter返回计数
override public int Count1 {
get { return sysStatus.Count1; }
}
override public int Count2 {
get { return sysStatus.Count2 ; }
}
override public int Count3 {
get { return sysStatus.Count3 ; }
}
override public int Count4 {
get { return sysStatus.Count4 ; }
}
override public int Count5 {
get { return sysStatus.Count5 ; }
}
每个实例都在自己独特的端口上启动。我已经在收到的未经请求的消息的回调函数上设置了断点,但是除了实际上要接收数据的实例之外的任何实例都没有中断,但都返回相同的计数。
答案 0 :(得分:0)
初始化sysStatus时,将其设置为SystemStatus.NullStatus,我假设它是一个静态SystemStatus实例。此赋值更新sysStatus变量以指向内存中的NullStatus对象 - 它不会复制该对象。通过sysStatus变量设置值时,它将更新SystemStatus.NullSTatus指向的同一对象,SystemStatus.NullSTatus是所有实例共享的静态对象。您可能希望将其更改为结构,或使用新的SystemStatus()而不是将sysStatus指向该静态实例。
编辑:以下是我的原始答案......我怀疑你问题的关键在于:
从每次收到UDP消息时触发的事件处理程序调用ParseSystemStatus函数
所有3个实例都已连线,以侦听PacketReceived事件。当调用OnPacketReceived方法并且它触发存储在PacketReceived中的事件时,将触发所有事件处理程序,这些事件处理程序被连线以侦听它。这意味着将为您的每个类实例单独调用client_UnsolicitedMessageReceived方法。
换句话说,现在你的系统的编写方式,你有1台UDP服务器。每次收到数据包时,它都会通知SuccinctClass的每个实例都收到了数据包。如果您想要不同的行为,您可能需要想出一种方法来指定您真正想要通知的实例,或者从SuccinctClass的实例中检测您是否真的想要对特定数据包执行操作或将其留给另一个数据包班级的实例。