【问题标题】:Best way to throw exceptions on query attempt c#在查询尝试c#中抛出异常的最佳方法
【发布时间】:2011-11-09 20:59:45
【问题描述】:

您好,我正在使用 C# 和实体框架(linq 到实体)开发一个 winform 应用程序。 假设以下场景:

在某个类的方法中,我用表单值设置值对象

 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”的分配和调用介于 try 和 catch 之间,因此如果触发了异常,MessageBox 将显示它。

然后在其他类中,我有 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()" 方法捕获,所以用户知道问题的根源。我希望你能理解我想要做什么。

谢谢

【问题讨论】:

    标签: c# winforms exception


    【解决方案1】:

    只需在 AgregaCliente() 方法中去掉你的 try/catch,异常就会自动冒泡。

    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 很好的答案。此外,如果你想对异常做一些事情,比如记录它,你可以删除'return false;'并将其替换为 'throw;'
    • 此外,由于该函数现在只能返回 true 或抛出异常,因此可能根本不需要 bool 返回值,您可以将其更改为 void。
    • 优秀的回答迪伦,谢谢。只是为了确保,如果抛出其他异常(如数据库上的重复键、格式不正确等),它也会冒泡吗?
    • 没错,任何未处理的异常都会自动冒泡给调用者。
    【解决方案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;
       }
    

    }

    【讨论】:

    • 不错的答案,您从 AgregaCliente 方法中删除了 try/catch,就像上面的答案一样。如果我需要扩展功能,我会使用您的建议,谢谢
    猜你喜欢
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 2019-02-16
    • 2018-05-19
    • 2011-09-21
    • 2020-09-18
    • 2022-06-12
    相关资源
    最近更新 更多