Лучший способ генерировать исключения при попытке запроса c#

#c# #winforms #exception

#c# #winforms #исключение

Вопрос:

Привет, я разрабатываю приложение winform с использованием C # и entity framework (linq для entities). Предположим, что следующий escenario:

В методе некоторого класса я устанавливаю и объект значений со значениями формы

  private void agrega_cliente_Click(object sender, EventArgs e)
 {
        cliente = new _Cliente();

        try
        {
            cliente.nombres = nom_cliente.Text;
            cliente.apellidoP = apellidoP_cliente.Text;
            cliente.apellidoM = apellidoM_cliente.Text;
            cliente.fechaNacimiento = fechaNacimientoPicker.Value.Date;

            if (operaciones.AgregaCliente(cliente, referencias))
            {
                MessageBox.Show("Cliente Agregado");
                this.Close();
            }
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
 }
  

Обратите внимание, что назначение и вызов метода «AgregaCliente» находятся между попыткой и перехватом, поэтому, если возникает исключение, окно сообщения покажет его.

Затем в другом классе у меня есть метод AgregaCliente, который вставляет значения в базу данных.

  public bool AgregaCliente(_Cliente cliente, ArrayList refes)
 {
        try
        {
            Cliente cli = new Cliente()
            {
                Nombres = cliente.nombres,
                ApellidoP = cliente.apellidoP,
                ApellidoM = cliente.apellidoM,
                FechaNac = cliente.fechaNacimiento
            };
            if (NombreExiste(cli))
                context.clientes.AddObject(cli);
            else
                throw new System.ArgumentException("El usuario ya existe");
            if (refes.Count != 0)
            {
                foreach (_Referencia elem in refes)
                    context.referencias_personales.AddObject(AgregaReferencia(elem));
            }
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            return false;
        }
        return true;
 }
  

Внутри этого метода есть вызов "NombreExiste()" , который проверяет, что пользователь еще не вставлен, если пользователь существует, генерируется исключение.

Итак, проблема здесь в том, что если в "AgregaCliente" методе генерируется исключение, я хочу, чтобы это исключение было перехвачено "agrega_cliente_Click()" методом, чтобы пользователь знал, из-за чего возникла проблема. Я надеюсь, вы понимаете, что я пытаюсь сделать.

Спасибо

Ответ №1:

Просто избавьтесь от вашей попытки / улова внутри метода AgregaCliente (), и исключение автоматически всплывет.

 public bool AgregaCliente(_Cliente cliente, ArrayList refes) 
{ 
    Cliente cli = new Cliente() 
    { 
        Nombres = cliente.nombres, 
        ApellidoP = cliente.apellidoP, 
        ApellidoM = cliente.apellidoM, 
        FechaNac = cliente.fechaNacimiento 
    }; 
    if (NombreExiste(cli)) 
        context.clientes.AddObject(cli); 
    else 
        throw new System.ArgumentException("El usuario ya existe"); 
    if (refes.Count != 0) 
    { 
        foreach (_Referencia elem in refes) 
            context.referencias_personales.AddObject(AgregaReferencia(elem)); 
    } 
    context.SaveChanges(); 

    return true; 
} 
  

Комментарии:

1. 1 Отличный ответ. Кроме того, если вы хотите что-то сделать с исключением, например, зарегистрировать его, вы можете удалить ‘return false;’ и заменить его на ‘throw;’

2. Кроме того, поскольку функция может только возвращать true или генерировать исключение сейчас, вероятно, вообще нет необходимости в возвращаемом значении bool, и вы можете изменить его на void.

3. Отличный ответ, Дилан, спасибо. Просто чтобы убедиться, что если возникнет другое исключение (например, дубликат ключа в базе данных, неправильный формат и т.д.), Оно также будет скопировано?

4. Это верно, любые необработанные исключения автоматически передаются вызывающему.

Ответ №2:

Проблема в том, что ваш метод AgregaCliente () перехватывает все исключения и просто проглатывает их. Вместо того, чтобы перехватывать все исключения с помощью:

     catch (Exception ex)
    {
        return false;
    }
  

Вы должны перехватывать только определенные исключения, которые вы можете обработать, и позволять остальным проходить по цепочке вызовов. Однако вы должны знать, что генерирование исключений очень «дорого» для программы. C # выполняет большую работу за кулисами, когда генерируется исключение. Лучшим решением может быть использование кода возврата, чтобы указать вызывающим метод AgregaCliente() статус. Например:

 public enum AgregaClienteStatus
{
  Success = 0;
  ClientAlreadyExists = 1;
  Other = ??;  // Any other status numbers you want
}

 public AgregaClienteStatus AgregaCliente(_Cliente cliente, ArrayList refes)
 {

            Cliente cli = new Cliente()
            {
                Nombres = cliente.nombres,
                ApellidoP = cliente.apellidoP,
                ApellidoM = cliente.apellidoM,
                FechaNac = cliente.fechaNacimiento
            };
            if (NombreExiste(cli))
                context.clientes.AddObject(cli);
            else
                return AgregaClienteStatus.ClientAlreadyExists
            if (refes.Count != 0)
            {
                foreach (_Referencia elem in refes)
                    context.referencias_personales.AddObject(AgregaReferencia(elem));
            }
            context.SaveChanges();


        return AgregaClientStatus.Success;
 }
  

Конечно, эта функциональность также может быть достигнута с использованием постоянных целых чисел, если вам не нравятся перечисления.

Затем вы можете использовать этот возвращаемый статус для указания информации пользователю без затрат на исключение:

   var result = AgregaClient(cliente, refes);
  switch (result)
  {
    case AgregaClientStatus.Success:
         // Perform success logic
         break;
    case AgregaClientStatus.ClientAlreadyExists:
         MessageBox.Show("Client already exists");
         break;
    // OTHER SPECIAL CASES
    default:
         break;
   }
  

}

Комментарии:

1. Хороший ответ, и вы удалили try / catch из метода AgregaCliente, подобного приведенному выше ответу. В случае, если мне понадобится расширить функциональность, я воспользуюсь вашим предложением, спасибо