Class 成员在定义为静态或非静态时表现不同
Class member behave differently when define as static or non static
我有 WPF
应用程序,其中 PcapDotNet
DLL 测量我的机器 Interface Rate
。
这是Model
:
public class Interface
{
public PacketDevice PacketDevice { get { return livePacketDevice; } }
private DateTime _lastTimestamp;
private double _bitsPerSecond;
private double _packetsPerSecond;
private DateTime _lastTimestamp;
private static List<Interface> _machineInterfaces; // list of all machine interfaces
public void Start(Interface inf)
{
OpenAdapterForStatistics(inf.PacketDevice);
}
public void OpenAdapterForStatistics(PacketDevice selectedOutputDevice)
{
if (selectedOutputDevice != null)
{
using (PacketCommunicator statCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the output adapter
{
try
{
statCommunicator.Mode = PacketCommunicatorMode.Statistics; //put the interface in statstics mode
statCommunicator.ReceiveStatistics(0, StatisticsHandler); //start the main loop
}
catch (Exception)
{ }
}
}
}
private void StatisticsHandler(PacketSampleStatistics statistics)
{
DateTime currentTimestamp = statistics.Timestamp; //current sample time
DateTime previousTimestamp = _lastTimestamp; //previous sample time
_lastTimestamp = currentTimestamp; //set _lastTimestamp for the next iteration
if (previousTimestamp == DateTime.MinValue) //if there wasn't a previous sample than skip this iteration (it's the first iteration)
return;
double delayInSeconds = (currentTimestamp - previousTimestamp).TotalSeconds; //calculate the delay from the last sample
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
_packetsPerSecond = statistics.AcceptedPackets / delayInSeconds; //calculate packets per second
if (NewPointEventHandler != null)
NewPointEventHandler(_bitsPerSecond);
double value = _packetsPerSecond;
}
如您所见,Start
方法开始测量 Interface
速率并将值放入 2 个字段中:
_bitsPerSecond
和 _packetsPerSecond
.
所以在应用程序启动后我有这个字段:
List<Interface> _machineInterfaces;
读取我所有的机器界面。
之后我开始我的 Start
方法:
private void StartStatistics()
{
int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start(); // start my timer
}
- 好的,现在这是我的问题:
这是我的 Timer Tick Event
:
public RadObservableCollection<double> mbitPerSecondValue { get; private set; }
如果我的 BitsPerSecond
Class Interface member
定义为常规而不是 Static
它的值始终为零:
private void statisticsTimer_Tick(object sender, EventArgs e)
{
int index = listview.SelectedIndex;
double bps = Interface.MachineInterfaces[index].BitsPerSecond; // always zero !
mbitPerSecondValue.Add(bps);
}
如果 BitsPerSecond
定义为 static 一切都很好:
private void statisticsTimer_Tick(object sender, EventArgs e)
{
int index = listview.SelectedIndex;
double bps = Interface.BitsPerSecond;
mbitPerSecondValue.Add(bps);
}
所以我的问题是为什么?
编辑
目前我改变了我的功能:
private void StartStatistics()
{
int index = lvAdapters.SelectedIndex;
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
foreach (Interface item in Interface.MachineInterfaces)
item.Start();
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start();
}
我想要实现的是在我的机器上的每个接口上打开统计信息,但在第一个接口(我有 2 个)中我可以看到流量变化(BitsPerSecond)但在第二个接口中它始终为零(我确保通过此接口生成一些流量,因此它不应该为零)
嗯,很明显为什么它在定义为 static
时起作用:Interface
的所有实例都共享相同的 属性,因此当您从一个地方增加它的值时,新值随处自动可用。
但是作为常规的非静态 属性,您必须确保从您之前修改过的同一实例中读取。而你不是。
首先,您要创建一个新的 Interface
(我们称之为接口 A),然后调用它的 Start
,传递另一个 Interface
(我们称之为您从 Interface.MachineInterfaces
获得的接口 B) 作为参数:
private void StartStatistics()
{
...
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
};
...
}
在接口 A 的 Start
方法中,您正在订阅接口 B 的统计信息,但处理程序仍在接口 A 中:
public void Start(Interface inf)
{
OpenAdapterForStatistics(inf.PacketDevice);
}
public void OpenAdapterForStatistics(PacketDevice selectedOutputDevice)
{
...
statCommunicator.ReceiveStatistics(0, StatisticsHandler); //start the main loop
...
}
并且当调用接口 A 中的处理程序时,它会增加自己的 _bitsPerSecond
值。不是接口 B,而是接口 A。
private void StatisticsHandler(PacketSampleStatistics statistics)
{
...
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
...
}
但最后,您要检查接口 B 中 BitsPerSecond
的值,再次取自 Interface.MachineInterfaces
!
private void statisticsTimer_Tick(object sender, EventArgs e)
{
...
double bps = Interface.MachineInterfaces[index].BitsPerSecond; // always zero !
...
}
-- 建议的解决方案 1 --
你为什么不直接创建它,这样 Start
使用它自己的实例,这样你就不必为了使用它而创建一个新的 Interface
?
public void Start()
{
OpenAdapterForStatistics(this.PacketDevice);
}
这样你就可以做到:
private void StartStatistics()
{
int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
ThreadStart tStarter = delegate
{
Interface.MachineInterfaces[index].Start(); // send the selected interface
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start(); // start my timer
}
...您应该会在 Timer Tick 回调中获得所需的输出。
-- 建议的解决方案 2 --
如果您不想从 Interface.MachineInterfaces
中的原始接口调用 Start
,那么您必须将新接口存储在某种字典中,以便您可以访问它稍后从中得到 BitsPerSecond
:
private Dictionary<Interface, Interface> InterfaceDictionary = new Dictionary<Interface, Interface>();
private void StartStatistics()
{
int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start(); // start my timer
if (InterfaceDictionary.ContainsKey(Interface.MachineInterfaces[index]))
InterfaceDictionary[Interface.MachineInterfaces[index]] = inf;
else
InterfaceDictionary.Add(Interface.MachineInterfaces[index], inf);
}
并且在您的 Timer Tick 回调中,从关联的接口中获取数据,而不是从 Interface.MachineInterfaces
:
中的接口中获取数据
private void statisticsTimer_Tick(object sender, EventArgs e)
{
int index = listview.SelectedIndex;
var interface = InterfaceDictionary[Interface.MachineInterfaces[index]];
double bps = interface.BitsPerSecond;
mbitPerSecondValue.Add(bps);
}
对于你的第二个问题,尝试从不同的线程调用每个接口的 Start
。我看到的唯一可疑的事情是,也许 statCommunicator.ReceiveStatistics
正在阻塞线程并阻止其他接口启动。
这应该可以避免这个问题:
private void StartStatistics()
{
foreach (Interface item in Interface.MachineInterfaces)
{
ThreadStart tStarter = delegate
{
item.Start();
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
}
statisticsTimer.Start();
}
我有 WPF
应用程序,其中 PcapDotNet
DLL 测量我的机器 Interface Rate
。
这是Model
:
public class Interface
{
public PacketDevice PacketDevice { get { return livePacketDevice; } }
private DateTime _lastTimestamp;
private double _bitsPerSecond;
private double _packetsPerSecond;
private DateTime _lastTimestamp;
private static List<Interface> _machineInterfaces; // list of all machine interfaces
public void Start(Interface inf)
{
OpenAdapterForStatistics(inf.PacketDevice);
}
public void OpenAdapterForStatistics(PacketDevice selectedOutputDevice)
{
if (selectedOutputDevice != null)
{
using (PacketCommunicator statCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the output adapter
{
try
{
statCommunicator.Mode = PacketCommunicatorMode.Statistics; //put the interface in statstics mode
statCommunicator.ReceiveStatistics(0, StatisticsHandler); //start the main loop
}
catch (Exception)
{ }
}
}
}
private void StatisticsHandler(PacketSampleStatistics statistics)
{
DateTime currentTimestamp = statistics.Timestamp; //current sample time
DateTime previousTimestamp = _lastTimestamp; //previous sample time
_lastTimestamp = currentTimestamp; //set _lastTimestamp for the next iteration
if (previousTimestamp == DateTime.MinValue) //if there wasn't a previous sample than skip this iteration (it's the first iteration)
return;
double delayInSeconds = (currentTimestamp - previousTimestamp).TotalSeconds; //calculate the delay from the last sample
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
_packetsPerSecond = statistics.AcceptedPackets / delayInSeconds; //calculate packets per second
if (NewPointEventHandler != null)
NewPointEventHandler(_bitsPerSecond);
double value = _packetsPerSecond;
}
如您所见,Start
方法开始测量 Interface
速率并将值放入 2 个字段中:
_bitsPerSecond
和 _packetsPerSecond
.
所以在应用程序启动后我有这个字段:
List<Interface> _machineInterfaces;
读取我所有的机器界面。
之后我开始我的 Start
方法:
private void StartStatistics()
{
int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start(); // start my timer
}
- 好的,现在这是我的问题:
这是我的 Timer Tick Event
:
public RadObservableCollection<double> mbitPerSecondValue { get; private set; }
如果我的 BitsPerSecond
Class Interface member
定义为常规而不是 Static
它的值始终为零:
private void statisticsTimer_Tick(object sender, EventArgs e)
{
int index = listview.SelectedIndex;
double bps = Interface.MachineInterfaces[index].BitsPerSecond; // always zero !
mbitPerSecondValue.Add(bps);
}
如果 BitsPerSecond
定义为 static 一切都很好:
private void statisticsTimer_Tick(object sender, EventArgs e)
{
int index = listview.SelectedIndex;
double bps = Interface.BitsPerSecond;
mbitPerSecondValue.Add(bps);
}
所以我的问题是为什么?
编辑
目前我改变了我的功能:
private void StartStatistics()
{
int index = lvAdapters.SelectedIndex;
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
foreach (Interface item in Interface.MachineInterfaces)
item.Start();
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start();
}
我想要实现的是在我的机器上的每个接口上打开统计信息,但在第一个接口(我有 2 个)中我可以看到流量变化(BitsPerSecond)但在第二个接口中它始终为零(我确保通过此接口生成一些流量,因此它不应该为零)
嗯,很明显为什么它在定义为 static
时起作用:Interface
的所有实例都共享相同的 属性,因此当您从一个地方增加它的值时,新值随处自动可用。
但是作为常规的非静态 属性,您必须确保从您之前修改过的同一实例中读取。而你不是。
首先,您要创建一个新的 Interface
(我们称之为接口 A),然后调用它的 Start
,传递另一个 Interface
(我们称之为您从 Interface.MachineInterfaces
获得的接口 B) 作为参数:
private void StartStatistics()
{
...
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
};
...
}
在接口 A 的 Start
方法中,您正在订阅接口 B 的统计信息,但处理程序仍在接口 A 中:
public void Start(Interface inf)
{
OpenAdapterForStatistics(inf.PacketDevice);
}
public void OpenAdapterForStatistics(PacketDevice selectedOutputDevice)
{
...
statCommunicator.ReceiveStatistics(0, StatisticsHandler); //start the main loop
...
}
并且当调用接口 A 中的处理程序时,它会增加自己的 _bitsPerSecond
值。不是接口 B,而是接口 A。
private void StatisticsHandler(PacketSampleStatistics statistics)
{
...
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
...
}
但最后,您要检查接口 B 中 BitsPerSecond
的值,再次取自 Interface.MachineInterfaces
!
private void statisticsTimer_Tick(object sender, EventArgs e)
{
...
double bps = Interface.MachineInterfaces[index].BitsPerSecond; // always zero !
...
}
-- 建议的解决方案 1 --
你为什么不直接创建它,这样 Start
使用它自己的实例,这样你就不必为了使用它而创建一个新的 Interface
?
public void Start()
{
OpenAdapterForStatistics(this.PacketDevice);
}
这样你就可以做到:
private void StartStatistics()
{
int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
ThreadStart tStarter = delegate
{
Interface.MachineInterfaces[index].Start(); // send the selected interface
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start(); // start my timer
}
...您应该会在 Timer Tick 回调中获得所需的输出。
-- 建议的解决方案 2 --
如果您不想从 Interface.MachineInterfaces
中的原始接口调用 Start
,那么您必须将新接口存储在某种字典中,以便您可以访问它稍后从中得到 BitsPerSecond
:
private Dictionary<Interface, Interface> InterfaceDictionary = new Dictionary<Interface, Interface>();
private void StartStatistics()
{
int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
Interface inf = new Interface();
ThreadStart tStarter = delegate
{
inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
statisticsTimer.Start(); // start my timer
if (InterfaceDictionary.ContainsKey(Interface.MachineInterfaces[index]))
InterfaceDictionary[Interface.MachineInterfaces[index]] = inf;
else
InterfaceDictionary.Add(Interface.MachineInterfaces[index], inf);
}
并且在您的 Timer Tick 回调中,从关联的接口中获取数据,而不是从 Interface.MachineInterfaces
:
private void statisticsTimer_Tick(object sender, EventArgs e)
{
int index = listview.SelectedIndex;
var interface = InterfaceDictionary[Interface.MachineInterfaces[index]];
double bps = interface.BitsPerSecond;
mbitPerSecondValue.Add(bps);
}
对于你的第二个问题,尝试从不同的线程调用每个接口的 Start
。我看到的唯一可疑的事情是,也许 statCommunicator.ReceiveStatistics
正在阻塞线程并阻止其他接口启动。
这应该可以避免这个问题:
private void StartStatistics()
{
foreach (Interface item in Interface.MachineInterfaces)
{
ThreadStart tStarter = delegate
{
item.Start();
};
Thread thread = new Thread(tStarter);
thread.IsBackground = true;
thread.Start();
}
statisticsTimer.Start();
}