чтобы избежать нулей, как можно сформулировать лучшую логику для передачи результатов api объектам в моем проекте

#c# #null #argumentnullexception

Вопрос:

вот небольшая часть кода, если у кого-то есть идеи, не стесняйтесь подбадривать меня!

 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 )   Listlt;BinanceOrderBookEntrygt; 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 lt; 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)  {  } }  

Ответ №1:

Если я правильно понимаю архитектуру вашего приложения, добавление нескольких нулевых проверок может решить вашу проблему.

Ваши модели:

 public class ClassDetailOrder {  public BinanceOrderBook Book { get; set; }  public string Symbol { get; set; } }  public class BinanceOrderBook {  public Listlt;BinanceOrderBookEntrygt; Asks { get; set; }  public Listlt;BinanceOrderBookEntrygt; Bids { get; set; } }  public class BinanceOrderBookEntry {  public decimal Price { get; set; }  public decimal Quantity { get; set; } }  

Ваш массив ClassDetailOrder с некоторыми значениями (пример):

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

Вызов GetBook метода с различными параметрами:

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

И ваш GetBook метод (с некоторыми моими дополнениями, изменениями и комментариями):

 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 =gt; 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 = (Listlt;BinanceOrderBookEntrygt;)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 lt; remaining ? remaining - cost : remaining - amount;   totalCost = cost lt; remaining ? totalCost   cost : amount * orderPrice;   totalAmount = cost lt; remaining ? totalAmount   orderAmount : totalAmount   amount;   // Reversed if because of ternary replacements  if (cost gt;= 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; }  

Основная идея, которую вы должны понять, состоит в том, чтобы проверять каждый объект, допускающий обнуление, на возможное нулевое значение, где это возможно. В этом примере у нас, возможно, может быть 8 объектов, которые могут быть null и могут вызвать NullReferenceException . И ты сможешь справиться со всеми ними:

  1. Для array оф ClassDetailOrder (чтобы иметь возможность искать ClassDetailOrder в нем предметы);
  2. Для указанного pair значения (чтобы избежать исключения null при использовании нижнего регистра ToLower() );
  3. Для каждого ClassDetailOrder (чтобы избежать нулевых исключений при поиске Book );
  4. Для ClassDetailOrder результата at (если методом никто не был найден FirstOrDefault );
  5. Для Book (чтобы быть уверенными, что мы можем получить доступ к нему Asks / Bids спискам);
  6. За предоставленную type стоимость (чтобы быть уверенным, что вы можете принять надлежащие List (запросы или ставки или любые другие, которые у вас будут));
  7. Для List (чтобы быть уверенным, что List по крайней мере пусто, но не равно нулю);
  8. Для BinanceOrderBookEntry элемента в foreach цикле List (чтобы убедиться, что мы можем получить доступ к его Price свойствам и Quantity свойствам).

Вы можете обрабатывать проверки на нуль так, как вы хотите, или возвращать значение, которое вы хотите, или изменять if значение s на is not null ( != null ).

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