- P82 示例代码
原文:
// 错误设计
public struct PositiveInteger
{
private int value;
public PositiveInteger(int value)
{
if (value <= 0) throw new ArgumentException(...);
_value = value
}
public override string ToString()
{
return _value.ToString();
}
}
更正为:
// 错误设计
public struct PositiveInteger
{
private int _value; // 译者注:英文原本中此处为字段名为 value,此处更正为 _value
public PositiveInteger(int value)
{
if (value <= 0) throw new ArgumentException(...);
_value = value
}
public override string ToString()
{
return _value.ToString();
}
}
- P89 示例代码
原文:
[Flags]
public enum WatcherChangeTypes
{
None = 0,
Created = 0x0002,
Deleted = 0x0004,
Changed = 0x0008,
Renamed = 0x0016,
}
更正为:
[Flags]
public enum WatcherChangeTypes
{
None = 0,
Created = 0x0002,
Deleted = 0x0004,
Changed = 0x0008,
Renamed = 0x0010,
}
- P91 示例代码
原文:
[Flags]
public enum MemberScopes
{
None = 0,
nstance = 0x4,
Static = 0x8,
}
更正为:
[Flags]
public enum MemberScopes
{
None = 0,
Instance = 0x4,
Static = 0x8,
}
- P113 第二段
√ CONSIDER 建议显式实现接口成员来模拟
差异变体(在``覆写''成员中的更改参数或返回类型)
- P141 第一段示例代码
// 该集合类型没有类型限制
public class SomeCollection<T> { ... }
// 非泛化的扩展类型
public sealed class SomeCollectionComparisons {
// 该方法只有集合中的元素为可比较的值是才生效
public static T GetMinimumValue<T>(
this SomeCollection<T> source) where T : IComparable<T> {
...
}
}
更正为:
// 该集合类型没有类型限制
public class SomeCollection<T> { ... }
// 非泛化的扩展类型
public static class SomeCollectionComparisons {
// 该方法只有集合中的元素为可比较的值是才生效
public static T GetMinimumValue<T>(
this SomeCollection<T> source) where T : IComparable<T> {
...
}
}
- P152 第二段示例代码
public partial struct DateTimeOffset {
public static implicit operator DateTimeOffset(DateTime dateTime) {...}
public static operator<(DateTimeOffset left, DateTimeOffset right){...}
}
更正为:
public partial struct DateTimeOffset {
public static implicit operator DateTimeOffset(DateTime dateTime) {...}
public static bool operator< (DateTimeOffset left, DateTimeOffset right){...}
}
- P184 最后一段示例代码
原文:
public Directory {
public Collection<string> GetFilenames(){
return new FilenameCollection(this);
}
private class FilenameCollection : Collection<string> {
...
}
}
更正为:
public class Directory {
public Collection<string> GetFilenames(){
return new FilenameCollection(this);
}
private class FilenameCollection : Collection<string> {
...
}
}
- P198 第三段
KRZYSZTOF CWALINA 请记住,将代码中所抛出的异常变更为该异常的子类型,并不是一种破坏性的变更。例如,如果你的框架的第一个版本抛出
FileNotFoundExcption
FooException
, 在该库的任何后续版本中,你都可以抛出FileNotFoundExcption
FooException
的子类型,而且不会破坏针对库的前一个版本所编译的代码。 这意味着,当有疑虑时,我会考虑先不去创建新的异常类型,直到你确定你需要它们。在这一点上,你可以通过继承当前抛出的类型来创建一个新的异常类型。 有时,这可能会导致稍显奇怪的异常继承结构(例如,继承自FileNotFoundExcption
InvalidOperationException
的自定义异常), 但与使你的库中拥有不必要的异常类型相比,这并不是什么大问题,这些不必要的异常类型使库更加复杂,增加了开发成本,增加了工作集,等等。
- P198 第四段
× AVOID 避免创建调用时可能导致系统故障的 API。如果的确会出现这样的故障,应该调用
FileNotFoundExcption
Environment.FailFast
,而不是在系统故障发生时抛出异常。系统故障是指开发者或程序无法处理的错误。好一点的是,在可复用库中,系统故障十分罕见。它们大多是由执行引擎引起的。在这种情况下, 停止进程的最好方法是调用
FileNotFoundExcption
Environment.FailFast
,它记录了系统的状态——这对问题诊断非常有用。
- P198 第六段
√ DO 要合理地抛出最具体(派生最末端)的异常。
例如,如果在参数传入了空值,应该抛出
FileNotFoundExcption
ArgumentNullException
,而不是它的基类FileNotFoundExcption
ArgumentException
。
- P199 第一段
JEFFREY RICHTER 直接抛出
FileNotFoundExcption
System.Exception
——它是所有符合 CLS 的异常的共同基类——始终都是不正确的。
- P199 第二段
BRENT RECTOR 正如后面详细描述的那样,直接捕获
FileNotFoundExcption
System.Exception
也几乎都是错误的行为。
-
P258 第一段 ...基于任务的异步模式可以直接使用这些类型手动实现,或者结合语言特性支持(如 C# 中的 async/await,Visual Basic .NET 中的
asyncAsync/Await,以及 F# 中的 async/let!/use!/do!)。该模式由以下元素组成: -
P259 第二段示例代码的注释
原文:
// 正确:支持 Cancellation 作为可选参数
public Task WriteAsync(
string text,
CancellationToken cancellationToken = default) { ... }
更正为:
// 正确:支持 CancellationToken 作为可选参数
public Task WriteAsync(
string text,
CancellationToken cancellationToken = default) { ... }
- P266 第二段示例代码
原文:
public readonly struct SomeResult {
public int CalculatedResult { get; }
public string UpdatedValue { get; }
public DivisionResult(int result, string updatedValue) { ... }
}
更正为:
public readonly struct SomeResult {
public int CalculatedResult { get; }
public string UpdatedValue { get; }
public SomeResult(int result, string updatedValue) { ... }
}
- P270 倒数第二条准则
× DON'T 不要在异
常步方法中调用Task.Wait()
或读取Task.Result
属性;相反,使用 await。
- P275 - P276 示例代码
原文:
// 错误
public Task<int> MaxAsync(
IAsyncEnumerable<int> source,
CancellationToken cancellationToken = default) {
int max = int.MinValue;
bool hasValue = false;
// cancellationToken 没有被使用
async foreach (int value in source.ConfigureAwait(false)) {
hasValue = true;
if (value > max) {
max = value;
}
}
return hasValue ? max : throw new InvalidOperationException();
}
// 正确
public Task<int> MaxAsync(
IAsyncEnumerable<int> source,
CancellationToken cancellationToken = default) {
int max = int.MinValue;
bool hasValue = false;
// cancellationToken 被传入了迭代器中
async foreach (
int value in source.WithCancellation(cancellationToken).ConfigureAwait(false)
) {
hasValue = true;
if (value > max) {
max = value;
}
}
return hasValue ? max : throw new InvalidOperationException();
}
更正为:
// 错误
public async Task<int> MaxAsync(
IAsyncEnumerable<int> source,
CancellationToken cancellationToken = default) {
int max = int.MinValue;
bool hasValue = false;
// cancellationToken 没有被使用
await foreach (int value in source.ConfigureAwait(false)) {
hasValue = true;
if (value > max) {
max = value;
}
}
return hasValue ? max : throw new InvalidOperationException();
}
// 正确
public async Task<int> MaxAsync(
IAsyncEnumerable<int> source,
CancellationToken cancellationToken = default) {
int max = int.MinValue;
bool hasValue = false;
// cancellationToken 被传入了迭代器中
await foreach (
int value in source.WithCancellation(cancellationToken).ConfigureAwait(false)
) {
hasValue = true;
if (value > max) {
max = value;
}
}
return hasValue ? max : throw new InvalidOperationException();
}
原文:
// 不需要 WithCancellation(cancellationToken),
// 因为它已经被传入了 ValueGenerator。
async foreach (int value in
ValueGenerator(10, 5, cancellationToken).ConfigureAwait(false)) {
...
}
更正为:
// 不需要 WithCancellation(cancellationToken),
// 因为它已经被传入了 ValueGenerator。
await foreach (int value in
ValueGenerator(10, 5, cancellationToken).ConfigureAwait(false)) {
...
}
- P308 最后一段
√ DO 当需要对查询进行检查时,要使用
Expression<Func<...>>
作为参数,而不是Func<...>
。 更多细节见9.6.59.6.2.3 节。
- P309 第二段
另一个使用表达式的原因是执行时优化。例如,一个
排序的有序的列表可以用二进制搜索二分查找实现查找(Where 语句), 这比标准的IEnumerable<T>
或IQueryable<T>
实现要高效得多。