C# 在C中正确处理异常和日志#

C# 在C中正确处理异常和日志#,c#,exception,logging,C#,Exception,Logging,假设我有一个类Person,具有不同数据类型的不同属性,我的主方法中有以下代码: Person p1 = new Person { Name = inputName, DateOfBirth = inputDOB, Height = height, Weight = weight, Passport = inputPassport }; 现在,假设高度的赋值引发了一个异常,例如InvalidCast

假设我有一个类Person,具有不同数据类型的不同属性,我的主方法中有以下代码:

Person p1 = new Person
    {
        Name = inputName,
        DateOfBirth = inputDOB,
        Height = height,
        Weight = weight,
        Passport = inputPassport
    };
现在,假设高度的赋值引发了一个异常,例如InvalidCastException,代码将停止执行,并且可能会记录一些东西,以防我有一个记录表。 问题是,从日志中,我无法确切地理解哪一行和赋值抛出了异常

是否有任何方法可以捕获异常,并能够记录(数据库中的某个位置)哪个赋值引发异常,以及在这种情况下针对哪种类型的强制转换(例如double to DateTime)


更新: 最后,我通过这样做解决了我的问题:

  • 更新代码,使其首先创建对象(无需 设置属性),然后一行一行地设置属性 时间
  • 在每行之间添加一个连接 刚刚设置的变量的值
  • 在我的捕获中,我记录了连接字符串,因此快速查看该字符串基本上可以告诉我在抛出异常之前成功执行的最后一行代码

  • 这是一个众所周知的问题。以下是一些与此相关的链接:

    我还使用
    C#7.3(.net4.7.2)
    C#8(.netcore3.1)
    测试了您的场景,问题仍然存在。因此,如果使用对象初始值设定项且其中一个初始值设定项值引发异常,则无法从堆栈跟踪中知道哪个初始值设定项值导致异常


    解决方法

    让我们考虑下一类<代码>人<代码>:

    class Person
    {
        public string Name { get; set; }
        public DateTime DateOfBirth { get; set; }
        public int Age { get; set; }
    }
    
    并假设使用下一个代码创建类
    Person
    的实例:

    // Return type of the methods getName(), getDateOfBirth() and getAge() is object.
    // Each of this methods can return invalid value, for example, method getAge()
    // can return string value causing InvalidCastException.
    Person p = new Person
    {
        Name = (string) getName(),
        DateOfBirth = (DateTime) getDateOfBirth(),
        Age = (int) getAge()
    };
    
    如果某个初始值设定项值(例如,将方法
    getName()
    的结果强制转换为
    string
    数据类型)引发异常,我们将无法知道哪个初始值设定项值是异常的原因,因为堆栈跟踪中的行号将指向行
    Person p=new Person

    要解决此问题,我们可以拒绝使用对象初始值设定项,而使用旧式对象初始化:

    Person p = new Person();
    p.Name = (string) getName();
    p.DateOfBirth = (DateTime) getDateOfBirth();
    p.Age = (int) getAge();
    
    现在,如果发生异常,我们将能够知道发生异常的确切行号

    在这里,我们必须在可读性(对象初始值设定项)和获取初始化期间异常原因的更准确信息之间进行选择

    还有其他解决办法。例如,我们可以在对象初始值设定项中使用初始值设定项值之前检查它们:


    结论

    这是一个众所周知的问题。它仍然存在,尚未修复。我们可以通过拒绝使用对象初始值设定项和使用属性设定项(
    p.Name=(string)getName()
    )来解决这个问题。还可以使用另一种解决方法(例如,在使用对象初始值设定项之前检查初始值设定项值)


    我们应该小心地使用对象初始值设定项。如果初始化值可以抛出异常,我们应该考虑使用属性设置器初始化对象(PNE=(String)GETNAMEL()/代码>),因为它将简化调试。

    在创建人之前,可以对所有输入运行验证方法来消除异常。将它们转换为正确的类型,然后创建Person对象。@Jawad但这意味着为所需的任何类型的强制转换创建一个方法,对吗?当强制转换失败时,是否有任何标准的方法来检查和记录并保存关于哪个语句抛出错误以及针对哪种类型的转换的信息?隐式强制转换应该。您的代码示例缺少任何显式转换。如果这些属性是属性,您将在异常堆栈跟踪的顶部看到set_Height()。它们无论如何都不应该是字段(封装),或者您正在谈论隐式类型转换异常?然后,正如@JohnWu所评论的那样。