自定义异常 C#

Custom Exception C#

我想创建自己的自定义异常(用于我自己的实践),我有 Man class 并且我想检查名称(因此它不是空的、空的并且只有英文字符。 我不确定我这样做是否正确, 1.do 我需要编写代码来处理自定义异常中的错误(如果发生)class?还是在男人的setter? 2. 我应该在哪里使用 "throw new Exception" 以获得最佳实践? 3. 欢迎任何关于我的代码的comments\improvements。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace prog
{
    class Program
    {
        static void Main(string[] args)
        {

            try
            {
                Man p = new Man("Dan");

            }
            catch (Exception e)
            {
                throw new NameNotValidException(e.Message);
            }


        }
}

class Man
{
    private string name;

    public string Name
    {
        get { return name; }
        set
        {
            if (name == "" || name == null)
            {
                throw new NameNotValidException("error");
            }

            name = value;
        }
    }

    public Man(string name)
    {
        this.name = name;
    }

}

class NameNotValidException : Exception
{
    public NameNotValidException()
    {
        Console.WriteLine("Please Write a valid name!");
    }

    public NameNotValidException(string message)
        : base(message)
    {
    }

    public NameNotValidException(string message, Exception inner)
        : base(message, inner)
    {
    }
}

谢谢!

如果您想创建自定义异常,只需扩展任何异常 类,例如:

class MyCustomException : System.Exception
{}

你可以做到 throw new MyCustomException();

  1. 在这种情况下,抛出 ArgumentNullException 更为合适。 你最终使用哪个异常(你自己的或ArgumentNullException)并不重要,也不会改变下面代码的结构或者你应该如何处理一个例外。
  2. 您要检查 value,而不是 setter 中的 name
  3. 处理调用代码处的异常。如果调用代码未设计为处理异常,则不要捕获该异常或使用 throw 重新抛出以保留堆栈跟踪。
  4. 在代码因...而失败的位置抛出异常(本例中的值无效
  5. 小心你的 getter/setter 代码,你检查了错误的值并且还绕过了构造函数中的 setter 在这种情况下它永远不会抛出异常开始。

你的男人class.

public class Man {
    public Man(string name)
    {
        // notice capital N for Name so it is set on the property, not the field
        // this will execute the setter for the Name property
        this.Name = name;
    }

    public Man(){} // optional, but do not include the parameterized constructor you had as it sets the private fields directly OR include additional validation

    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentNullException("Name cannot be null or empty");
            name = value;
        }
    }
}

正在调用处理异常的代码。

try
{
    // use parameterized constructor
    Man p = new Man("Dan"); 

    // or use an initializer
    Man p = new Man{Name = "Dan"}; 

    // the above initializer is actually short for
    Man p = new Man(); 
    p.Name = "Dan"; 
}
catch (ArgumentException e)
{
    Console.WriteLine("Error occurred!! Do something...");
}

当你抛出一个异常时,你说的是 "Hey, something went wrong!",这样调用者就可以做一些事情了。异常的责任是说出到底出了什么问题,而不是如何处理它。所以你应该从异常中删除 Console.WriteLine("Please Write a valid name!"); 。相反,将它放在实际预期该错误的代码中 - 即您的 Main 方法。 静态无效主要(字符串[]参数) {

        try
        {
            Man p = new Man("Dan");
        }
        catch (NameNotValidException e)
        {
            Console.WriteLine("Please Write a valid name! " + e.Message);
        }

另请注意,我在 catch 块中使用的是 NameNotValidException,而不是 Exception。作为一般规则,您应该在处理错误时尽可能具体 - 这就是我们首先创建自定义异常的原因 =)。例如,假设您添加了一个 Age 属性,它会引发 AgeNotValidException。如果你捕获 Exception e,你会为每个错误说 "Please Write a valid name!",包括无效的年龄。通过分别处理每个异常类型,您可以不同地处理每个错误。

关于你的 "throw new Exception" 问题,你做对了:当你不能做某事时,你应该抛出异常 - 在这种情况下,你无法设置用户名,因为给定的名字是无效的。但是,您还应该尝试更具体地使用错误消息,以使错误更容易从中恢复:在您的情况下,您可以将其更改为 throw new NameNotValidException("Name can't be empty"); 的内容,这样您就可以告诉用户不要只是名称无效,还有具体原因。

如果你只想更改消息,你可以使用这个: throw new Exception("File check failed!");

由于您需要检查多种类型的无效输入(非空、空和仅英文字符),我的建议是为无效输入类型创建带有 属性 的自定义异常。示例如下:

class InvalidInputCustomException : Exception
{
    public string InputExceptionType { get; set; }

    public InvalidInputCustomException(string inputExceptionType)
    {
        InputExceptionType = inputExceptionType;
    }
}

然后你需要创建你的 class Man,其中设置访问器将检查输入(在此代码中的关键字值)和代码行 - 抛出新的 InvalidInputCustomException .. - 具有相应的输入异常类型在此自定义异常构造函数中将包含在内。此 class 示例如下:

class Man
{
    private string _name;

    public Man(string name)
    {
        this.Name = name;
    }
    public string Name
    {
        get { return _name; }
        set
        {
            if (value == null)
            {
                throw new InvalidInputCustomException("null is not valid for input.");
            }
            else if (value == string.Empty)
            {
                throw new InvalidInputCustomException("empty is not valid for input.");
            }
            else
            {
                foreach (char ch in value)
                {
                    if (!(ch >= 'A' && ch <= 'Z') && !(ch >= 'a' && ch <= 'z') &&
                        !(ch >= '0' && ch <= '9'))
                    {
                        throw new InvalidInputCustomException($"non English character {ch} is " +
                            $"not valid for input."); ;
                    }
                }
            }
            _name = value;
        }
    }
}

必须在初始化 Man class 对象的地方捕获抛出的异常,其 属性 名称试图设置(例如:

p.Name = inputString

或通过此对象构造函数,如下面的代码示例所示)。 控制台应用代码示例如下:

class Program
{
    static void Main(string[] args)
    {

        Console.WriteLine("Enter name and press key Enter:");
        string inputString = Console.ReadLine();
        try
        {
            Man p = new Man(inputString);
            Console.WriteLine($"Entered name - {p.Name} - is valid.");
        }
        catch (InvalidInputCustomException ex)
        {
            Console.WriteLine($"Invalid input type - {ex.InputExceptionType}. Please enter valid name.");
        }
        catch (Exception ex)
        {

            Console.WriteLine("Unhandled exception " + ex.Message);
        }
        Console.WriteLine("Press any key to finish the program.");
        Console.ReadLine();
    }
}

代码示例更多的是为了理解自定义异常。在实际应用中,需要避免在用户信息输入相关的情况下抛出异常——在这种情况下,必须使用数据验证工具。在实际应用程序中创建自定义异常期间,必须至少提供一个无参数构造函数,最佳做法是添加三个额外的构造函数:带字符串、带字符串和异常,用于序列化。