自定义异常C#
我想创建我自己的自定义异常(用于我自己的实践),我有Man类,我想检查名称(所以它不是空的,空的,只有英文字符)。 我不确定我是否做对了, 1.我是否需要在自定义异常类或人工设置器中编写处理错误(如果发生)的代码? 2.我应该在哪里使用“抛出新异常”作为最佳实践? 3.欢迎对我的代码提出任何意见\改进自定义异常C#,c#,object,custom-exceptions,C#,Object,Custom Exceptions,我想创建我自己的自定义异常(用于我自己的实践),我有Man类,我想检查名称(所以它不是空的,空的,只有英文字符)。 我不确定我是否做对了, 1.我是否需要在自定义异常类或人工设置器中编写处理错误(如果发生)的代码? 2.我应该在哪里使用“抛出新异常”作为最佳实践? 3.欢迎对我的代码提出任何意见\改进 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System
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
{}
您可以执行抛出新的MyCustomException();
ArgumentNullException
)并不重要,也不会改变下面代码的结构或您应该如何处理异常。值
,而不是名称
throw
重新刷新以保留堆栈跟踪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...");
}
当您抛出异常时,您说的是“嘿,出了什么问题!”,因此调用方可以对此采取措施。异常的责任是说明到底出了什么问题,而不是如何处理。因此您应该删除
控制台。WriteLine(“请写一个有效的名称!”)
从异常中删除。相反,将其放在实际预期该错误的代码中,即您的Main方法。
静态void Main(字符串[]参数)
{
try
{
Man p = new Man("Dan");
}
catch (NameNotValidException e)
{
Console.WriteLine("Please Write a valid name! " + e.Message);
}
还请注意,我在catch块中使用的是NameNotValidException
,而不是Exception
。一般来说,在处理错误时,您应该尽可能具体-这就是为什么我们首先创建自定义异常=)。例如,假设您添加了一个Age属性,该属性引发AgentValidException。如果捕获异常e
,您将对每个错误(包括无效的Age)说“请编写一个有效的名称!”。通过分别处理每个异常类型,您可以以不同的方式处理每个错误
关于你的“抛出新异常”问题,你做得对:当你不能做某事时,你应该抛出异常-在这种情况下,你无法设置用户名,因为给定的名称无效。但是,你也应该尝试更具体地显示错误消息,以使错误更容易恢复:在你的情况下,你可以将其更改为按照
抛出新名称NotValidException(“名称不能为空”);
这样,您不仅可以告诉用户名称无效,还可以告诉用户确切原因。如果您只想更改消息,您可以使用以下方法:
抛出新异常(“文件检查失败!”);
由于需要检查几种类型的无效输入(非空、空和仅英文字符),我的建议是使用无效输入类型的属性创建自定义异常。示例如下:
class InvalidInputCustomException : Exception
{
public string InputExceptionType { get; set; }
public InvalidInputCustomException(string inputExceptionType)
{
InputExceptionType = inputExceptionType;
}
}
然后,您需要创建一个类Man,在该类中,将检查输入(在此代码关键字值中)的set accessor,并将包含代码行-throw new InvalidInputCustomException..-以及此自定义异常构造函数中相应的输入异常类型。该类示例如下:
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;
}
}
}
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();
}
}
或通过此对象构造函数(如下面的代码示例所示)。
控制台应用程序代码的示例如下:
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;
}
}
}
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();
}
}
代码示例更多用于理解自定义异常。在实际应用程序中,您需要避免在与输入用户信息相关的情况下引发异常-在这种情况下,必须使用数据验证工具。在实际应用程序中创建自定义异常时,必须至少提供无参数构造函数和最佳做法是添加三个额外的构造函数:使用字符串、字符串和异常进行序列化。在这种情况下,更适合抛出
ArgumentNullException
。此外,您还希望检查值
,而不是名称
。例如,您的捕获应该处理异常,而不是引发异常一个新的。它必须是this.Name
而不是this.Name
-否则您不使用setter方法。您也不应该捕获异常并创建相同的新异常。您可以使用throw;
来进一步抛出相同的异常(您将在日志中看到)。但问题是关于他自己对自定义异常的实践。@Matt-是否用自定义异常替换ArgumentNullException
无关紧要,上面的代码结构将保持不变。谢谢!您启动“Dan”的方式有什么不同我是这样做的?@Coder123-你的重载构造函数直接设置私有字段name
,这样属性name
上的set
er就从来没有被真正调用过。这迫使你调用类型上的公共成员,比如name
。请参阅更新的代码,它显示了对象初始值设定项的实际含义@Coder123的ort-如果您想在构造函数中捕获Name
,并验证传入值,您有2个选项。1)在构造函数中使用该检查来验证参数。缺点是您有更多(双精度)代码.2)将值分配给构造函数中的Name
属性,然后属性上的set
将验证并可能引发异常。