c# - 为什么有时会收到此 NullReferenceException?
问题描述
这是一段有时会引发异常的代码:
Pendings = ClientCode.PendingOrders.Select(x => new DisplayPending()
{
ItemCode = ClientCode.Items.First(y => y.Id == x.ItemCode).Id,
ItemName = ClientCode.Items.First(y => y.Id == x.ItemCode).Name,
OrderNo = x.BuyOrderNo == 0 ? x.SellOrderNo : x.BuyOrderNo,
OrderType = x.OrderType == OrderType.Buy ? "Buy" : "Sell",
PartyCode = x.PartyCode,
Price = x.Price,
Quantity = x.Quantity
});
这是消息:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
x was null.
PendingOrders
是一个ObservableCollection
,它有 500 多个项目。
编辑
这是我填充扩展的方式ObservableCollection
:
public class AsyncObsetion<T> : ObservableCollection<T>
{
SynchronizationContext context = SynchronizationContext.Current;
readonly object _lock = new object();
public AsyncObsetion() { BindingOperations.EnableCollectionSynchronization(this, _lock); }
public AsyncObsetion(IEnumerable<T> list) : base(list) { BindingOperations.EnableCollectionSynchronization(this, _lock); }
void RaiseCollectionChanged(object param) => base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
void RaisePropertyChanged(object param) => base.OnPropertyChanged((PropertyChangedEventArgs)param);
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaiseCollectionChanged(e);
else context.Send(RaiseCollectionChanged, e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaisePropertyChanged(e);
else context.Send(RaisePropertyChanged, e);
}
public void InsertRange(IEnumerable<T> items)
{
this.CheckReentrancy();
foreach (var item in items)
this.Items.Add(item);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
当Client
连接到 时Server
,它会发送 6 个,这些 6 个byte[]
被添加到 8个AsyncObsetion<T>
名为Items
、NewsCollection
、Issued
、BuyOrders
、SellOrders
、PendingOrders
、ExecutedOrders
和MyExecutedOrders
客户端。这段代码负责处理byte[]
客户端从服务器获取的代码:
var tasks = new List<Task>();
tasks.Add(Task.Run(() =>
{
for (int i = 0; i < header.ItemSize; i += Constants.itemSize)
{
var item = PacMan<ItemStruct>.Unpack(itemArray.Skip(i).Take(Constants.itemSize).ToArray());
Items.Add(new Item()
{
Id = item.Id,
Name = item.Name,
Cap = item.Cap,
Floor = item.Floor,
Mid = item.Floor + ((item.Cap - item.Floor) / 2),
Securities = item.Securities,
Owners = item.Owners,
Govt = item.Govt,
Institutions = item.Institutions,
Foreign = item.Foreign,
Public = item.Public,
PerSecurity = PacMan<PerSecurityFinancialsStruct>.ArrayToList<PerSecurityFinancials>(item.PerSecurity),
Dividends = PacMan<DividendStruct>.ArrayToList<Dividend>(item.Dividends),
InitialSecurity = item.InitialSecurity
});
}
}).ContinueWith(t =>
{
if (header.HasExecuted) GetExOrders(header.ExecutedSize, execArray);
if (header.HasNews) AddNews(newsArray.ToArray());
}));
tasks.Add(Task.Run(() => { if (header.HasBuy) GetOrders(header.BuySize, buyArray, "buy"); }));
tasks.Add(Task.Run(() => { if (header.HasSell) GetOrders(header.SellSize, sellArray, "sell"); }));
tasks.Add(Task.Run(() => AddIssue(issueArray.ToArray())));
Task.WaitAll(tasks.ToArray());
hasReceivedData = true;
App.Current.Dispatcher.Invoke(() => CommandManager.InvalidateRequerySuggested());
OnConnected();
OrderVM.ItemCode = Items.First().Id;
e.Completed += Receive;
e.SetBuffer(headerBuffer, 0, headerBuffer.Length);
if (!e.AcceptSocket.ReceiveAsync(e)) Receive(null, e);
OnConnected()
是一个事件,当它被触发时,客户端开始创建Pendings
out of的过程PendingOrders
,该过程由buyArray
and组成sellArray
。我认为这就是问题所在,我相信有时会以某种方式OnConnected()
被解雇。Task.WaitAll(tasks.ToArray())
如果有人感兴趣,这就是GetOrders
:
void GetOrders(int size, IEnumerable<byte> array, string type)
{
var orderList = new List<AllOrder>();
var pendingList = new List<AllOrder>();
for (int i = 0; i < size; i += Constants.orderSize)
{
var order = PacMan<AllOrderStruct>.Unpack(array.Skip(i).Take(Constants.orderSize).ToArray());
AddInitNewOrder(order, orderList, pendingList);
}
if (type == "buy") CheckNumberAndAdd(orderList, BuyOrders);
else CheckNumberAndAdd(orderList, SellOrders);
CheckNumberAndAdd(pendingList, PendingOrders);
}
这是AddInitNewOrder
:
void AddInitNewOrder(AllOrderStruct order, List<AllOrder> orders, List<AllOrder> pendingOrders)
{
var o = new AllOrder();
o.Action = order.Action;
o.OrderType = order.OrderType;
o.ItemCode = order.ItemCode;
o.BrokerName = order.BrokerName;
o.PartyCode = order.PartyCode;
o.Price = order.Price;
o.Quantity = order.Quantity;
o.BuyOrderNo = order.BuyOrderNo;
o.SellOrderNo = order.SellOrderNo;
orders.Add(o);
if (o.BrokerName == BrokerName) pendingOrders.Add(o);
}
这是CheckNumberAndAdd
:
void CheckNumberAndAdd<T>(List<T> normList, AsyncObsetion<T> obsList)
{
var count = normList.Count;
if(count > 50)
{
obsList.InsertRange(normList.Take(count - 50));
var remaining = normList.Skip(count - 50).ToList();
for (int i = 0; i < remaining.Count; i++) obsList.Insert(0, remaining[i]);
}
else for (int i = 0; i < count; i++) obsList.Insert(0, normList[i]);
}
如果我在GetOrders
函数中设置断点,我会看到pendingList
从 483 个项目sellArray
和从 494 个项目buyArray
,所以我总共有 977 个项目。所以我应该总是得到 977 个项目,PendingOrders
但是如果我删除GetOrders
断点并在方法中设置断点Subscribe
,该方法与该事件挂钩,ClientCode.OnConnected += Subscribe;
我看到PendingOrders
有时会得到少于 977 个项目。
解决方案
解决该问题的一种方法是像这样包装最后三行GetOrders
方法:
App.Current.Dispatcher.Invoke(() =>
{
if (type == "buy") CheckNumberAndAdd(orderList, BuyOrders);
else CheckNumberAndAdd(orderList, SellOrders);
CheckNumberAndAdd(pendingList, PendingOrders);
});
这行得通。
推荐阅读
- mongodb - 如何让 fiware-orion 容器连接到 aws 上同一集群中的 mongodb 容器?
- spring-boot - 当从同一子网中的另一个 IP 地址卷曲时,Spring Boot Tomcat 没有响应
- python - Operations on existing Excel sheet using Pandas
- python-3.x - 这个 powerset 函数的时间和空间复杂度是多少?
- c - Isn't A in A[m][n] a pointer(drawing analogy from when we define 2 dimensional matrix using pointers)
- android - How to lock auto exposure in android using camera2 api
- asp.net - Listbox Control (SelectionMode = Multiple) dosen't load all data in sql-server?
- forms - HtmlUnit not finding form and not handling postback
- java - Custom json when using javers library
- docker - Can we run docker on already created image (Ubuntu)