C# 正在引发正确类型的异常
在我的代码中,我经常遇到这样的情况:C# 正在引发正确类型的异常,c#,.net,exception,C#,.net,Exception,在我的代码中,我经常遇到这样的情况: public void MyMethod(string data) { AnotherClass objectOfAnotherClass = GetObject(data); if (objectOfAnotherClass == null) throw new WhatExceptionType1("objectOfAnotherClass is null."); if (objectOfAnotherClass
public void MyMethod(string data)
{
AnotherClass objectOfAnotherClass = GetObject(data);
if (objectOfAnotherClass == null)
throw new WhatExceptionType1("objectOfAnotherClass is null.");
if (objectOfAnotherClass.SomeProperty < 0)
throw new WhatExceptionType2("SomeProperty must not be negative.");
}
public void MyMethod(字符串数据)
{
其他类的另一个类objectOtherClass=GetObject(数据);
if(objectOfOtherClass==null)
抛出新的WhatExceptionType1(“ObjectOfOtherClass为null”);
if(objectOfOtherClass.SomeProperty<0)
抛出新的WhatExceptionType2(“SomeProperty不能为负”);
}
假设GetObject
使用了一些不受我控制的外部库,如果data
不存在对象,则该库返回null
,并将负的SomeProperty
视为有效状态,因此不会引发异常。进一步想象一下,如果没有其他类的对象,则MyMethod
无法工作,如果使用负的SomeProperty
,则没有意义
在这种情况下,WhatExceptionType1/2
应该抛出哪些异常
基本上我有四个选择:
- 1)
InvalidOperationException
,因为在上述条件下,MyMethod
没有意义。另一方面,指南(以及VS中的Intellisense)指出,如果方法所属的对象处于无效状态,则应抛出InvalidOperationException。现在,对象本身没有处于无效状态。相反,输入参数data
和基于此参数的一些其他操作会导致MyMethod
无法再运行的情况
- 2)
ArgumentException
,因为有方法可以使用的数据值和方法不能使用的其他值。但是我不能通过单独检查数据来检查这一点,我必须在决定之前调用其他操作
- 3)
异常
,因为我不知道要使用哪种其他异常类型,而且因为所有其他预定义的异常都感觉过于专业化,不适合我的情况
- 4)
MyCustomException
(我自己的异常类型派生自exception
)。这似乎总是一个选项,但我担心,当我开始遵循此模式时,我必须为许多不同的错误条件定义许多特殊的异常类
还有其他更好的选择吗?赞成或反对这些选择的理由是什么
提前感谢您的反馈 使用ObjectNotFoundException怎么样。这将正确地描述情况。如果存在有意义的内置异常,我将使用它们。如果不是,则滚动您自己的异常是有意义的——即使它是扩展异常的空类——因为这允许您检测特定的异常类型。例如,如果您刚刚抛出异常,您如何知道异常是因为其他类的objectofotherclass
为null,并且它不是在GetObject
中引发的某个异常
总之:特定异常更好,因为您可以(潜在地)诊断特定情况并从中恢复。因此,请使用内置的.NET异常(如果它们足够),或者滚动您自己的异常
编辑:我应该澄清,我很少使用现有的异常,并在其中添加消息。如果异常类型告诉您错误,而不必调试、生成异常,然后检查消息以了解问题所在,则会使代码更具可读性。这实际上取决于您计划如何在应用程序中处理异常。自定义异常在try/catch情况下很好,但try/catch也很昂贵。如果您不打算捕获和处理自定义异常,那么:抛出新异常(“索引超出范围:SomeProperty不能为负值”);与自定义异常一样有用
public class InvalidStateException : ApplicationException
{
...
}
在代码中:
// test for null
if(objectOfAnotherClass == null) throw new NullReferenceException("Object cannot be null");
// test for valid state
if(objectOfAnotherClass.SomeProperty < 0) throw new InvalidStateException("Object is in an invalid state");
//测试空值
如果(ObjectOfOtherClass==null)抛出新的NullReferenceException(“对象不能为null”);
//有效状态测试
如果(ObjectOfOtherClass.SomeProperty<0)抛出新的InvalidStateException(“对象处于无效状态”);
如果不是两种情况,至少在第一种情况下,我的投票将是ArgumentException
;ArgumentExceptions应该抛出,引号是“当提供给方法的参数之一无效时”。如果MyMethod无法按照MyMethod的预期使用参数data
创建另一个类的有效实例,则该参数在MyMethod中无效
请理解,除非您计划捕获不同类型的异常并以不同的方式处理它们,否则抛出哪个异常实际上并不重要。有些异常(如ArgumentNullException)基于很少的信息创建自定义消息,因此易于设置和本地化,而另一些异常(如SQLException)则有关于出错原因的更具体的数据,但如果您只想抛出一个说“Oops!”的异常,那么所有这些都是多余的。首先,对错误进行分类。埃里克·利珀特(Eric Lippert)是我见过的最好的分类:致命的、骨瘦如柴的、令人烦恼的和外源性的。你的例外不会是致命的;这可能是一个:愚蠢的,烦躁的,或外生的
如果您可以说对于正确的输入name
,您知道GetObject
将返回一个对您的方法有意义的对象,那么这个错误就是愚蠢的。换句话说,导致这些异常的唯一原因是调用MyMethod
的代码中的错误。在这种情况下,您使用的异常类型实际上并不重要,因为您无论如何都不应该在生产中看到它——ArgumentException
(如果问题出在name
)或invalidoOperationexception
(如果问题出在定义MyMethod
的对象的状态)在这种情况下是不错的选择,但不应记录特定的异常类型(或
ObjectCreateException: // The call to GetObject() returned null<br />
InvalidObjectException: // The object returned by GetObject() is invalid
// (because the property < 0)
/// <summary>
/// A general, base error for GS3 applications </summary>
[Serializable]
public class Gs3Exception : ApplicationException {
/// <summary>
/// Initializes a new instance of the <see cref="Gs3Exception"/> class </summary>
public Gs3Exception() {}
/// <summary>
/// Initializes a new instance of the <see cref="Gs3Exception"/> class </summary>
/// <param name="message">A brief, descriptive message about the error </param>
public Gs3Exception(string message) : base(message) {}
/// <summary>
/// Initializes a new instance of the <see cref="Gs3Exception"/> class
/// when deserializing </summary>
/// <param name="info">The object that holds the serialized object data </param>
/// <param name="context">The contextual information about the source or
/// destination.</param>
public Gs3Exception(SerializationInfo info, StreamingContext context) : base(info, context) { }
/// <summary>
/// Initializes a new instance of the <see cref="Gs3Exception"/> class
/// with a message and inner exception </summary>
/// <param name="Message">A brief, descriptive message about the error </param>
/// <param name="exc">The exception that triggered the failure </param>
public Gs3Exception(string Message, Exception exc) : base(Message, exc) { }
}
/// <summary>
/// An object queried in an request was not found </summary>
[Serializable]
public class ObjectNotFoundException : Gs3Application {
private string objectName = string.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="ObjectNotFoundException"/> class </summary>
public ObjectNotFoundException() {}
/// <summary>
/// Initializes a new instance of the <see cref="ObjectNotFoundException"/> class </summary>
/// <param name="message">A brief, descriptive message about the error</param>
public ObjectNotFoundException(string message) : base(message) {}
/// <summary>
/// Initializes a new instance of the <see cref="ObjectNotFoundException"/> class </summary>
/// <param name="ObjectName">Name of the object not found </param>
/// <param name="message">A brief, descriptive message about the error </param>
public ObjectNotFoundException(string ObjectName, string message) : this(message) {
this.ObjectName = ObjectName;
}
/// <summary>
/// Initializes a new instance of the <see cref="ObjectNotFoundException"/> class.
/// This method is used during deserialization to retrieve properties from
/// the serialized data. </summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">The contextual information about the source or
/// destination.</param>
public ObjectNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) {
if (null != info) {
this.objectName = info.GetString("objectName");
}
}
/// <summary>
/// When serializing, sets the <see cref="T:System.Runtime.Serialization.SerializationInfo"/>
/// with information about the exception. </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds
/// the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="info"/> parameter is a null reference (Nothing in Visual Basic) </exception>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*"/>
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="SerializationFormatter"/>
/// </PermissionSet>
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
public override void GetObjectData(SerializationInfo info, StreamingContext context) {
base.GetObjectData(info, context);
// 'info' guaranteed to be non-null (base.GetObjectData() will throw an ArugmentNullException if it is)
info.AddValue("objectName", this.objectName);
}
/// <summary>
/// Gets or sets the name of the object not found </summary>
/// <value>The name of the object </value>
public string ObjectName {
get { return objectName; }
set { objectName = value; }
}
}
public void MyMethod(AnotherClass data)
{
if (data == null)
throw new ArgumentNullException("data is null.");
if (data.SomeProperty < 0)
throw new ArgumentException("data.SomeProperty must not be negative.");
...
}