0

here is a small part of the code if anyone has ideas feel free to hoit me up!

public decimal getBook(string pair, decimal amount, string type, string operation, bool division = true)
{
    try
    {   
        //book is null                    
        BinanceOrderBook book = null;

        foreach (var item in Program.array)
            if ((item as Program.ClassDetailOrder).symbol == pair.ToLower())
            {
                book = (item as Program.ClassDetailOrder).book; break;
            }

        // 'lst' is also null nut lst depends on book to not be null. lst is a list but created on the results of the ifs below  (ask and bid are api calls )

        List<BinanceOrderBookEntry> lst = null;
        if (type == "asks")
            lst = book.Asks;
        if (type == "bids")
            lst = book.Bids;

        decimal[] arrayValue = new decimal[2];
        arrayValue[0] = arrayValue[1] = 0;
        decimal orderPrice = 0;
        decimal orderAmount = 0;
        decimal totalCost = 0;
        decimal totalAmount = 0;
        decimal remaining = amount;
        decimal cost = 0;

        foreach (var item in lst)
        {
            orderPrice = item.Price;
            orderAmount = item.Quantity;
            cost = orderPrice * orderAmount;
            if (cost < remaining)
            {
                remaining -= cost;
                totalCost += cost;
                totalAmount += orderAmount;
            }
            else
            {
                //finished
                remaining -= amount;
                totalCost += amount * orderPrice;
                totalAmount += amount;
                if (division)
                {
                    arrayValue[0] = Math.Round(amount / (totalCost / totalAmount), 8);
                    arrayValue[1] = Math.Round(amount / orderPrice, 8);
                }
                else
                {
                    arrayValue[0] = Math.Round((totalCost / totalAmount) * amount, 8);
                    arrayValue[1] = Math.Round(orderPrice * amount, 8);
                }
                return arrayValue[0];
            }
        }
    }
    catch (Exception ex)
    {
    }
}
Auditive
  • 1,607
  • 1
  • 7
  • 13

1 Answers1

0

If I correctly understand your application architecture, adding a few null-checks may solve your issue.

Your models:

public class ClassDetailOrder
{
    public BinanceOrderBook Book { get; set; }
    public string Symbol { get; set; }
}

public class BinanceOrderBook
{
    public List<BinanceOrderBookEntry> Asks { get; set; }
    public List<BinanceOrderBookEntry> Bids { get; set; }
}

public class BinanceOrderBookEntry
{
    public decimal Price { get; set; }
    public decimal Quantity { get; set; }
}

Your array of ClassDetailOrder with some values (exampled):

private readonly ClassDetailOrder[] array = new ClassDetailOrder[]
{
    // Item 0
    null, 
    // Item 1
    new ClassDetailOrder
    {
        Book = new BinanceOrderBook
        {
            Asks = new List<BinanceOrderBookEntry>()
            {
                new BinanceOrderBookEntry { Price = 50, Quantity = 5 }
            }
        },
        Symbol = "book1"
    },
    // Item 2
    new ClassDetailOrder
    {
        Book = new BinanceOrderBook
        {
            Bids = new List<BinanceOrderBookEntry>()
            {
                new BinanceOrderBookEntry { Price = 100, Quantity = 10 }
            }
        },
        Symbol = "book2"
    },
};

Calling GetBook method with different parameters:

private void GetSomeBooks()
{
    GetBook("Book0", 1, "asks", "");
    GetBook(null, 2, "bids", "");
    GetBook("Book2", 3, "asks", "");
    GetBook("Book1", 4, null, "");
}

And your GetBook method (with few my additions, changes and comments):

public decimal GetBook(string pair, decimal amount, string type, string operation, bool division = true)
{
    // Default value
    var result = -1.0M;

    try
    {
        if (array is null)
        {
            // Handle in some way that "Array of ClassDetailOrders was null."
            return result;
        }

        if (string.IsNullOrEmpty(pair))
        {
            // Handle in some way that "Pair value must be specified."
            return result;
        }
 
        // Getting first Book from not-null(!) ClassDetailOrder,
        // which Symbol matches to provided "pair" value
        var book = array.FirstOrDefault(item => item?.Symbol == pair.ToLower())?.Book;

        // Book will be null if:
        // - all ClassDetailOrders in array was null
        // - no ClassDetailOrder with some Symbol that match to pair.ToLower() was found
        // - Book property of founded ClassDetailOrder was null by itself


        // Checking Book is null or not and go out from method if null
        if (book is null)
        {
            // Handle in some way that "Specified Book wasn't found."
            return result;
        }

        // If Book wasn't null, initializing List
        var lst = (List<BinanceOrderBookEntry>)null;
 
        // Provided "type" value also may be null or empty
        if (string.IsNullOrEmpty(type))
        {
            // Handle in some way that "Book Type must be specified."
            return result;
        }
          
        switch (type)
        {
            case "asks":
                lst = book.Asks;
                break;
            case "bids":
                lst = book.Bids;
                break;
        }

        // Same null-check as for Book above, but for List now
        if (lst is null)
        {
            // Handle in some way that "Book items of provided Type was null.";
            return result;
        }

        decimal[] arrayValue = new decimal[2] { 0M, 0M };
        decimal orderPrice = 0, orderAmount = 0, totalCost = 0, totalAmount = 0, cost = 0;
        decimal remaining = amount;

        foreach (var item in lst)
        {
            // Same null-check as for Book and List above
            if (item is null)
            {
                // Handle in some way that item was null, e.g.:
                continue;
                // or 
                return result;
            }

            orderPrice = item.Price;
            orderAmount = item.Quantity;
            cost = orderPrice * orderAmount;

            remaining = cost < remaining ? remaining - cost : remaining - amount;    
            totalCost = cost < remaining ? totalCost + cost : amount * orderPrice;    
            totalAmount = cost < remaining ? totalAmount + orderAmount : totalAmount + amount;

            // Reversed if because of ternary replacements
            if (cost >= remaining)
            {
                arrayValue[0] = division
                                ? Math.Round(amount / (totalCost / totalAmount), 8)
                                : Math.Round(totalCost / totalAmount * amount, 8);

                arrayValue[1] = division
                                ? Math.Round(amount / orderPrice, 8)
                                : Math.Round(orderPrice * amount, 8);

                result = arrayValue[0];
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

    return result;
}

The main idea, that you should understand, is to check every nullable object for possible null value where you can. In this example we possibly may have 8 objects, which could be null and may cause NullReferenceException. And you can handle them all:

  1. For array of ClassDetailOrder (to be able search for ClassDetailOrder items in it);
  2. For provided pair value (to avoid null exception when lowercasing with ToLower());
  3. For each ClassDetailOrder (to avoid null exceptions while searching for Book);
  4. For ClassDetailOrder at result (if no one was found by FirstOrDefault method);
  5. For Book (to be sure that we can access it's Asks/Bids lists);
  6. For provided type value (to be sure be can take proper List (Asks or Bids or any other you will have));
  7. For List (to be sure, that List at least empty, but not null);
  8. For BinanceOrderBookEntry item in foreach loop over List (to be sure we can access its Price and Quantity properties).

You can handle null-checks in a way you wish or return value you wish or reverse ifs to is not null (!= null) way.

You can tests different values to try cover all null-checks and test them.

Auditive
  • 1,607
  • 1
  • 7
  • 13