我这里有很大的问题。我有一个 MVP 应用程序,其中有一个模型可以处理与外部设备通信的实现。在应用程序中,我创建了 4 个此类的实例。每个实例使用唯一的 IP 和端口通过 UDP 套接字与其外部设备进行通信。
现在,对于所有初始测试,一切似乎都很好,因为我有 4 个视图,每个视图都显示了每个唯一设备的计数。对于测试,我总是只连接到一个设备,而其他 3 个连接什么也不做,但是视图总是按预期显示计数为零。
当我开始以编程方式创建单个 log4net 记录器以根据计时器触发记录每个实例的计数时,问题就出现了。我发现每个日志文件都记录了相同的计数!我以为这是我的 log4net 实现,但是在调试时,我在调试器中为自己看到每个实例都返回相同的计数。
当模型的实例被创建时,它们都被传递给一个演示者,该演示者持有对每个模型的引用。每个模型都有一个唯一的字符串标识符,这就是我在调试时知道正在查看哪个实例的方式(除了 IP 和端口)。
另外,我应该注意,计数是在接收到一个未经请求的 UDP 数据包时设置的,该数据包从未出现在 3 个实例上。
我的继承如下。
HeadModel
-HeadModelAbstract
--SubModel
---SubModelAbstract
引用的计数在子模型中。这样做是因为我需要一个类来与具有一组有限功能的基本级设备对话。然而,更高级的设备将具有该功能以及附加功能。我最初想传递接口,但发现这样做会隐藏子模型中的属性和方法,我仍然想公开这些属性和方法,所以我选择了你看到的抽象实现。
感谢所有能够做到这一点并尝试提供帮助的人。
摘要 - 为什么一个类的 4 个唯一实例都为相同的非静态属性返回相同的值?
更新:这是杂项代码
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 ; }
}
每个实例都在其自己的唯一端口上启动。我已经在回调函数上设置了断点,用于接收未经请求的消息,但对于除实际用于接收数据的实例之外的任何实例都不会中断,但所有实例都返回相同的计数。