C# 同一类的多个实例都为非静态属性返回相同的值
我这里的问题很严重。我有一个MVP应用程序,我有一个模型来处理与外部设备对话的实现。在应用程序中,我创建了这个类的4个实例。每个实例使用唯一的IP和端口通过UDP套接字与其外部设备通信 现在,对于所有的初始测试,一切似乎都很好,因为我有4个视图,每个视图都显示了每个设备的唯一计数。对于测试,我总是只连接到一个设备,而其他3个连接什么也不做,但是这些视图总是显示出预期的零计数 当我开始以编程方式创建单个log4net记录器,根据计时器触发记录每个实例的计数时,问题就出现了。我发现每个日志文件都记录了相同的计数!我以为这是我的log4net实现,但当调试时,我自己在调试器中看到每个实例都返回相同的计数 创建模型的实例时,它们都会传递给一个演示者,该演示者持有对每个模型的引用。每个模型都有一个唯一的字符串标识符,这是我在调试时知道正在查看哪个实例的方式(除了IP和端口) 另外,我应该注意到,计数是在接收到未经请求的UDP数据包时设置的,其中3个实例从未收到该数据包 我的天性如下 人头模型C# 同一类的多个实例都为非静态属性返回相同的值,c#,properties,multiple-inheritance,abstract,multiple-instances,C#,Properties,Multiple Inheritance,Abstract,Multiple Instances,我这里的问题很严重。我有一个MVP应用程序,我有一个模型来处理与外部设备对话的实现。在应用程序中,我创建了这个类的4个实例。每个实例使用唯一的IP和端口通过UDP套接字与其外部设备通信 现在,对于所有的初始测试,一切似乎都很好,因为我有4个视图,每个视图都显示了每个设备的唯一计数。对于测试,我总是只连接到一个设备,而其他3个连接什么也不做,但是这些视图总是显示出预期的零计数 当我开始以编程方式创建单个log4net记录器,根据计时器触发记录每个实例的计数时,问题就出现了。我发现每个日志文件都记录
-HeadModelAbstract
--子模型
---子模型摘要 引用的计数在子模型中。之所以这样做,是因为我需要一个类来与具有有限功能的设置级别的基本设备进行通信。但是,更先进的设备将具有该功能和附加功能。我最初想传递接口,但发现这样做会隐藏子模型中的属性和方法,我仍然想公开这些属性和方法,所以我使用了您看到的抽象实现 感谢所有走到这一步来尝试和帮助的人 摘要-为什么一个类的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];
}
}
每个实例都在其自己的唯一端口上启动。我在回调函数上为收到的未经请求的消息设置了断点,但除了实际要接收数据的实例外,任何实例都不会中断,但所有实例都返回相同的计数。初始化sysStatus时,将其设置为SystemStatus.NullStatus,我假设它是静态SystemStatus实例。此赋值更新sysStatus变量以指向内存中的NullStatus对象-它不会复制该对象。当您通过sysStatus变量设置值时,它将更新SystemStatus.NullSTatus指向的同一对象,该对象是所有实例共享的静态对象。您可能希望将其更改为结构,或者使用新的SystemStatus()而不是将sysStatus指向该静态实例 编辑:下面是我最初的答案 我怀疑你问题的关键在于: ParseSystemStatus函数由事件处理程序调用,该事件处理程序在每次收到UDP消息时都会触发 您的所有3个实例都连接起来以侦听PacketReceived事件。当调用OnPacketReceived方法并触发PacketReceived中存储的事件时,将触发所有连接到它的事件处理程序。这意味着将为类的每个实例分别调用client_UnsolicitedMessageReceived方法
换句话说,按照现在编写系统的方式,您有一个UDP服务器。每次收到数据包时,它都会通知SuccurcClass的每个实例已收到该数据包。如果您想要不同的行为,您可能必须想出一种方法来指定您真正想要通知的实例,或者从一个SuccuctClass实例中检测您是否真的想对一个特定的数据包执行操作,或者让它由该类的另一个实例执行。属性是由实例本身设置的还是由其他东西设置的?您是否至少可以显示一些代码,例如计数的成员变量声明,修改计数的代码,调用修改计数的代码?嗯,看起来这是因为我缺乏知识。我的印象是,由于每个实例都有自己的UdpServer,因此当触发事件时,它只会通知创建它的实例,因为该实例是唯一的对象。您的意思似乎是,每当对象调用连接到其事件处理程序的方法时,它都会在类的所有当前实例上调用该方法?我只是尝试了一些方法,并在每次收到数据包时添加了一条日志语句。当它被接收时,我记录它已被接收,并且接收它的实例由一个字符串标识。日志仅记录了一个实例的接收情况?日志看起来是这样的…
数据包接收设备1
数据包接收设备1
如果它正在通知所有实例,我应该看到设备2、设备3等。现在我更困惑了。您可能是对的,只是看起来您的所有UdpServer实例都在同一端口上侦听(从您的注释来看,端口3000)。如果是这样的话,要么它们都可以被触发,要么其他两个侦听器可能根本就不会绑定到端口或侦听。事实上,我收回了这一切——我只是看到了我认为真正的问题,而我以前完全忽略了这一点。我会修改我的回答,就是这样。你是摇滚明星!谢谢你的帮助。我真的很感激。
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 ) );
}
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 ; }
}