处理XDocument.Save(string)
执行期间可能抛出的异常的最佳做法是什么?
我发现可以抛出XmlExceptions
- 我是否还要检查IOExceptions
?
这适用于高可用性应用程序,我希望观察并捕获与磁盘空间相关的错误。我应该为IOException
和XMLException
执行多次捕获吗? Stack Overflow推荐什么?
答案 0 :(得分:2)
这取决于。由于IOException
和XmlException
意味着两个完全不同的东西,我会单独处理它们,只要您正在执行其他操作,然后记录并通知用户。
通过其他我的意思是,例如,捕获IOException
并尝试写入其他位置,如备份接收器。对于XMLException
,触发向XML供应商发出的XML无效的通知。
如果你只需要记录和忽略,就没有必要单独捕捉它们。如果没有完成日志记录,只需让它在调用链上运行。
答案 1 :(得分:1)
这可能是一项艰巨的任务。考虑一下您正在执行的代码流:
public void Save(string fileName, SaveOptions options)
{
XmlWriterSettings xmlWriterSettings = XNode.GetXmlWriterSettings(options);
if (this.declaration != null)
{
if (!string.IsNullOrEmpty(this.declaration.Encoding))
{
try
{
xmlWriterSettings.Encoding = Encoding.GetEncoding(this.declaration.Encoding);
}
catch (ArgumentException ex)
{
}
}
}
using (XmlWriter writer = XmlWriter.Create(fileName, xmlWriterSettings))
this.Save(writer);
}
在其中,XmlWriter.Create(fileName, xmlWriterSettings)
单独会引发以下异常:
有无数原因。此外,此代码(明确抛出这些异常):
private unsafe void Init(string path, FileMode mode, FileAccess access, int rights, bool useRights, FileShare share, int bufferSize, FileOptions options, Win32Native.SECURITY_ATTRIBUTES secAttrs, string msgPath, bool bFromProxy, bool useLongPath, bool checkHost)
{
if (path == null)
throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path"));
if (path.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
FileSystemRights fileSystemRights = (FileSystemRights) rights;
this._fileName = msgPath;
this._exposedHandle = false;
FileShare fileShare = share & ~FileShare.Inheritable;
string paramName = (string) null;
if (mode < FileMode.CreateNew || mode > FileMode.Append)
paramName = "mode";
else if (!useRights && (access < FileAccess.Read || access > FileAccess.ReadWrite))
paramName = "access";
else if (useRights && (fileSystemRights < FileSystemRights.ReadData || fileSystemRights > FileSystemRights.FullControl))
paramName = "rights";
else if (fileShare < FileShare.None || fileShare > (FileShare.ReadWrite | FileShare.Delete))
paramName = "share";
if (paramName != null)
throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Enum"));
if (options != FileOptions.None && (options & (FileOptions) 67092479) != FileOptions.None)
throw new ArgumentOutOfRangeException("options", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
if ((!useRights && (access & FileAccess.Write) == (FileAccess) 0 || useRights && (fileSystemRights & FileSystemRights.Write) == (FileSystemRights) 0) && (mode == FileMode.Truncate || mode == FileMode.CreateNew || (mode == FileMode.Create || mode == FileMode.Append)))
{
if (!useRights)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo", (object) mode, (object) access));
else
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&RightsCombo", (object) mode, (object) fileSystemRights));
}
else
{
if (useRights && mode == FileMode.Truncate)
{
if (fileSystemRights == FileSystemRights.Write)
{
useRights = false;
access = FileAccess.Write;
}
else
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileModeTruncate&RightsCombo", (object) mode, (object) fileSystemRights));
}
int dwDesiredAccess = useRights ? rights : (access == FileAccess.Read ? int.MinValue : (access == FileAccess.Write ? 1073741824 : -1073741824));
int maxPathLength = useLongPath ? Path.MaxLongPath : Path.MaxPath;
string path1 = Path.NormalizePath(path, true, maxPathLength);
this._fileName = path1;
if (path1.StartsWith("\\\\.\\", StringComparison.Ordinal))
throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported"));
Path.CheckInvalidPathChars(path1, true);
if (path1.IndexOf(':', 2) != -1)
throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported"));
bool flag1 = false;
if (!useRights && (access & FileAccess.Read) != (FileAccess) 0 || useRights && (fileSystemRights & FileSystemRights.ReadAndExecute) != (FileSystemRights) 0)
{
if (mode == FileMode.Append)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode"));
flag1 = true;
}
if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
{
FileIOPermissionAccess access1 = FileIOPermissionAccess.NoAccess;
if (flag1)
access1 |= FileIOPermissionAccess.Read;
if (!useRights && (access & FileAccess.Write) != (FileAccess) 0 || useRights && (fileSystemRights & (FileSystemRights.Write | FileSystemRights.DeleteSubdirectoriesAndFiles | FileSystemRights.Delete | FileSystemRights.ChangePermissions | FileSystemRights.TakeOwnership)) != (FileSystemRights) 0 || useRights && (fileSystemRights & FileSystemRights.Synchronize) != (FileSystemRights) 0 && mode == FileMode.OpenOrCreate)
{
if (mode == FileMode.Append)
access1 |= FileIOPermissionAccess.Append;
else
access1 |= FileIOPermissionAccess.Write;
}
AccessControlActions control = secAttrs != null && (IntPtr) secAttrs.pSecurityDescriptor != IntPtr.Zero ? AccessControlActions.Change : AccessControlActions.None;
new FileIOPermission(access1, control, new string[1]
{
path1
}, 0 != 0, 0 != 0).Demand();
}
share &= ~FileShare.Inheritable;
bool flag2 = mode == FileMode.Append;
if (mode == FileMode.Append)
mode = FileMode.OpenOrCreate;
if (FileStream._canUseAsync && (options & FileOptions.Asynchronous) != FileOptions.None)
this._isAsync = true;
else
options &= ~FileOptions.Asynchronous;
int dwFlagsAndAttributes = (int) (options | (FileOptions) 1048576);
int newMode = Win32Native.SetErrorMode(1);
try
{
string str = path1;
if (useLongPath)
str = Path.AddLongPathPrefix(str);
this._handle = Win32Native.SafeCreateFile(str, dwDesiredAccess, share, secAttrs, mode, dwFlagsAndAttributes, IntPtr.Zero);
if (this._handle.IsInvalid)
{
int errorCode = Marshal.GetLastWin32Error();
if (errorCode == 3 && path1.Equals(Directory.InternalGetDirectoryRoot(path1)))
errorCode = 5;
bool flag3 = false;
if (!bFromProxy)
{
try
{
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new string[1]
{
this._fileName
}, 0 != 0, 0 != 0).Demand();
flag3 = true;
}
catch (SecurityException ex)
{
}
}
if (flag3)
__Error.WinIOError(errorCode, this._fileName);
else
__Error.WinIOError(errorCode, msgPath);
}
}
finally
{
Win32Native.SetErrorMode(newMode);
}
if (Win32Native.GetFileType(this._handle) != 1)
{
this._handle.Close();
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles"));
}
else
{
if (this._isAsync)
{
bool flag3 = false;
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
try
{
flag3 = ThreadPool.BindHandle((SafeHandle) this._handle);
}
finally
{
CodeAccessPermission.RevertAssert();
if (!flag3)
this._handle.Close();
}
if (!flag3)
throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
}
if (!useRights)
{
this._canRead = (access & FileAccess.Read) != (FileAccess) 0;
this._canWrite = (access & FileAccess.Write) != (FileAccess) 0;
}
else
{
this._canRead = (fileSystemRights & FileSystemRights.ReadData) != (FileSystemRights) 0;
this._canWrite = (fileSystemRights & FileSystemRights.WriteData) != (FileSystemRights) 0 || (fileSystemRights & FileSystemRights.AppendData) != (FileSystemRights) 0;
}
this._canSeek = true;
this._isPipe = false;
this._pos = 0L;
this._bufferSize = bufferSize;
this._readPos = 0;
this._readLen = 0;
this._writePos = 0;
if (flag2)
this._appendStart = this.SeekCore(0L, SeekOrigin.End);
else
this._appendStart = -1L;
}
}
}
使用大量依赖项,这些依赖项可能会抛出自己的异常。
我的建议,首先要确保真的需要知道可能引发的每个可能的异常。正如约翰和我的谈话所述,在99%以上的情况下抛出什么异常并不重要,可以用同样的方式处理。
有关何时的更多信息,您可能 需要知道所有异常类型,请仔细阅读评论。
最后,如果你需要知道每个异常,请获取JetBrains dotPeek的副本并使用.NET Framework代码。