C# 在查询尝试时引发异常的最佳方法#

C# 在查询尝试时引发异常的最佳方法#,c#,winforms,exception,C#,Winforms,Exception,您好,我正在使用C#和实体框架(linq to entities)开发一个winform应用程序。 假设以下情况: 在某个类的方法中,我使用表单值设置值和值的对象 private void agrega_cliente_Click(object sender, EventArgs e) { cliente = new _Cliente(); try { cliente.nombres = nom_cliente.Tex

您好,我正在使用C#和实体框架(linq to entities)开发一个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());
        }
 }
请注意,对方法“agregaclient”的分配和调用介于try和catch之间,因此如果触发异常,MessageBox将显示它

在另一个类中,我有一个AgregCliente方法,它在数据库中插入值

 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;
 }
在这个方法中,有一个对
“nombrexist()”
的调用,它检查用户是否已经插入,如果用户存在,就会抛出一个异常

因此,这里的问题是,如果在
“agregaclient”
方法中抛出异常,我希望通过
“agrega\u client\u Click()”
方法捕获该异常,以便用户知道问题的根源。我希望你明白我想做什么


谢谢

只要去掉agregaclient()方法中的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; 
} 

只要去掉agregaclient()方法中的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; 
} 

问题是agregaclient()方法捕获所有异常并简单地将其吞并。而不是通过以下方式捕获所有异常:

    catch (Exception ex)
    {
        return false;
    }
您应该只捕获您可以处理的特定异常,并让其他异常放弃调用链。但是,您应该知道,抛出异常对于程序来说是非常“昂贵”的。当抛出异常时,C#在幕后做了大量工作。更好的解决方案可能是使用返回代码向agregaclient()方法的调用方指示状态。例如:

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

}

问题在于agregaclient()方法捕获所有异常并简单地将其吞没。而不是通过以下方式捕获所有异常:

    catch (Exception ex)
    {
        return false;
    }
您应该只捕获您可以处理的特定异常,并让其他异常放弃调用链。但是,您应该知道,抛出异常对于程序来说是非常“昂贵”的。当抛出异常时,C#在幕后做了大量工作。更好的解决方案可能是使用返回代码向agregaclient()方法的调用方指示状态。例如:

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回答得很好。此外,如果您想对异常执行某些操作(如记录异常),可以删除“return false;”并将其替换为“throw;”此外,由于该函数现在只能返回true或抛出异常,因此可能根本不需要bool返回值,您可以将其更改为void。出色的回答Dylan,谢谢。只是为了确保,如果引发其他异常(如数据库上的重复键、不正确的格式等),它也会冒泡?没错,任何未处理的异常都会自动冒泡到调用方那里。+1回答很好。此外,如果您想对异常执行某些操作(如记录异常),可以删除“return false;”并将其替换为“throw;”此外,由于该函数现在只能返回true或抛出异常,因此可能根本不需要bool返回值,您可以将其更改为void。出色的回答Dylan,谢谢。只是为了确保,如果引发其他异常(如数据库上的重复键、不正确的格式等),它也会冒泡?没错,任何未处理的异常都会自动冒泡到调用方。回答很好,您从AgregCliente方法中删除了try/catch,如上面的回答。如果我需要扩展功能,我将使用您的建议,谢谢您的回答,并且您从AgregCliente方法中删除了try/catch,如上面的回答。如果我需要扩展功能,我将使用您的建议,谢谢