自定义异常 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();
- 在这种情况下,抛出 ArgumentNullException 更为合适。 你最终使用哪个异常(你自己的或
ArgumentNullException
)并不重要,也不会改变下面代码的结构或者你应该如何处理一个例外。
- 您要检查
value
,而不是 setter 中的 name
。
- 处理调用代码处的异常。如果调用代码未设计为处理异常,则不要捕获该异常或使用
throw
重新抛出以保留堆栈跟踪。
- 在代码因...而失败的位置抛出异常(本例中的值无效)
- 小心你的 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();
}
}
代码示例更多的是为了理解自定义异常。在实际应用中,需要避免在用户信息输入相关的情况下抛出异常——在这种情况下,必须使用数据验证工具。在实际应用程序中创建自定义异常期间,必须至少提供一个无参数构造函数,最佳做法是添加三个额外的构造函数:带字符串、带字符串和异常,用于序列化。
我想创建自己的自定义异常(用于我自己的实践),我有 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();
- 在这种情况下,抛出 ArgumentNullException 更为合适。 你最终使用哪个异常(你自己的或
ArgumentNullException
)并不重要,也不会改变下面代码的结构或者你应该如何处理一个例外。 - 您要检查
value
,而不是 setter 中的name
。 - 处理调用代码处的异常。如果调用代码未设计为处理异常,则不要捕获该异常或使用
throw
重新抛出以保留堆栈跟踪。 - 在代码因...而失败的位置抛出异常(本例中的值无效)
- 小心你的 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();
}
}
代码示例更多的是为了理解自定义异常。在实际应用中,需要避免在用户信息输入相关的情况下抛出异常——在这种情况下,必须使用数据验证工具。在实际应用程序中创建自定义异常期间,必须至少提供一个无参数构造函数,最佳做法是添加三个额外的构造函数:带字符串、带字符串和异常,用于序列化。