-1

Here's piece of code where It throws the exception sometimes:

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
});

and here's the message:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

x was null.

PendingOrders is anObservableCollection and It has more than 500 items.

EDIT

Here's how I populate my extended 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));
    }
}

When Client connects to Server, it sends 6 byte[] which are added in 8 AsyncObsetion<T> named Items, NewsCollection, Issued, BuyOrders, SellOrders, PendingOrders, ExecutedOrders and MyExecutedOrders on client side. This piece of code is responible for handling those byte[] which client gets from server:

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() is an event and when it's fired client starts the process of creating Pendings out of PendingOrders, which is made out of buyArray and sellArray. I think here's the problem and I believe somehow OnConnected() gets fired before Task.WaitAll(tasks.ToArray()) sometimes. If someone is interested, here's what GetOrders does:

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);
}

here's 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);
}

and here's 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]);                         
}

If I set brekpoint in GetOrders function, I see pendingList gets 483 items from sellArray and 494 items from buyArray, so altogether I've 977 items. So I should get 977 Items in PendingOrders always BUT If I remove brekpoint in GetOrders and set breakpoint in Subscribe method, which is hooked into that event ClientCode.OnConnected += Subscribe; I see PendingOrders sometimes gets less than 977 items.

  • 3
    Does this answer your question? [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Pavel Anikhouski Dec 24 '19 at 14:11
  • 4
    you'r using `.First` keyword. If Id and itemcode not matched means, it gives error. Use `.FirstOrDefault(y => y.Id == x.ItemCode)` and try – sri harsha Dec 24 '19 at 14:12
  • @sriharsha, it has matching items. –  Dec 24 '19 at 14:15
  • @sriharsha .First will throw ArgumentNullException, not NullReferenceException – Ruben Martirosyan Dec 24 '19 at 14:15
  • 1
    @EmonHaque, Can you show the model of `DisplayPending`. Also, can you show sample values of `ClientCode.PendingOrders` and `ClientCode.Items` – sri harsha Dec 24 '19 at 14:18
  • 1
    What is the problem? Error message is quite verbose. It reads: _"... x was null"_. And `x` is referencing an item of the `PendingOrders` collection. Just make sure that all items are initialized and that you don't add `null` to the collection. Before you add an item to the collection check for `null` before you add items to the collection. `if (item != null) PendingOrders.Add(item)`. – BionicCode Dec 24 '19 at 14:20
  • @BionicCode, `PendingOrders` has more than 500 items in it! –  Dec 24 '19 at 14:23
  • So what? You where adding them at one point to the collection. Just add a `null` check: `if (item != null) PendingOrders.Add(item)`. – BionicCode Dec 24 '19 at 14:24
  • Alternatively use LINQ: `ClientCode.PendingOrders.Where(x => x != null).Select(x => ...)` – BionicCode Dec 24 '19 at 14:26
  • Null Coalescing Operator in C# in the fastest way to handle nullable type in LINQ. – XAMT Dec 24 '19 at 14:38
  • @XAMT It's noit faster. It's just syntactic sugar to improve readability. It's a simple comparison with `null` under the hood. – BionicCode Dec 24 '19 at 15:53

2 Answers2

1

As @BionicCode stated, you just have some null elements in the collection.

Just filter them out with .Where(x != null) or similar.
Although this might solve the problem, generally undetected null references are a hint about week points in the code.

Consider reinforcing your null check policy to avoid these errors in the future. The same framework allows you to perform checks on nullable objects, making the code cleaner and more robust.

https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types

Alvin Sartor
  • 1,333
  • 2
  • 14
  • 27
0

One way to solve the issue is to wrap the last three lines of GetOrders method like this:

App.Current.Dispatcher.Invoke(() =>
{
    if (type == "buy") CheckNumberAndAdd(orderList, BuyOrders);
    else CheckNumberAndAdd(orderList, SellOrders);
    CheckNumberAndAdd(pendingList, PendingOrders);
});

this works.