IDesign C#命名规范(翻译2.32)

1. Naming Conventions and Style 命名规范和代码风格

1. Use Pascal casing for type and method names and constants: 类型、方法和常量命名用Pascal风格,即首字母大写

public class SomeClass

{

const int DefaultSize = 100;

public void SomeMethod()

{ }

}

2. Use camel casing for local variable names and method arguments.局部变量和方法参数使用Camel风格。即首字母小写,后出现的单词首字母大写。

void MyMethod(int someNumber)

{

int number;

}

3. Prefix interface names with I 接口使用I前缀

interface IMyInterface

{...}

4. Prefix private member variables with m_. Use Pascal casing for the rest of a member

variable name following the m_.

私有变量使用m_前缀,其后单词用Pascal风格。

public class SomeClass

{

private int m_Number;

}

5. Suffix custom attribute classes with Attribute.自定义的属性类名使用Attribute后缀

6. Suffix custom exception classes with Exception.自定义的异常类名使用Exception后缀

7. Name methods using verb-object pair, such as ShowDialog().方法命名采用动宾式。如ShowDialog()。

8. Methods with return values should have a name describing the value returned, such

as GetObjectState().对于有返回值的方法,应该使用描述方法返回值的方法名,如GetObjectState()。

9. Use descriptive variable names. 使用有意义的变量名。

a) Avoid single character variable names, such as i or t. Use index or temp instead.

不要使用单个字符的变量名,如i或t。应使用index或temp

b) Avoid using Hungarian notation for public or protected members. 公共和保护的成员不要使用匈牙利命名法,即不要加数据类型前缀,如strName。

c) Do not abbreviate words (such as num instead of number). 不要缩写单词,比如number缩写成num

10. Always use C# predefined types rather than the aliases in the System namespace.

总是使用C#预定义的类型,而不是System命名空间中的别名。如:

用 object 不用Object

用string 不用String

用int 不用Int32

11. With generics, use capital letters for types. Reserve suffixing Type when dealing

with the .NET type Type. 当使用泛型时,使用大写字母作为类型。不要加Type后缀

//正确:

public class LinkedList<K,T>

{...}

//避免:

public class LinkedList<KeyType,DataType>

{...}

12. Use meaningful namespaces such as the product name or the company name. 使用有意义的命名空间,比如产品名或公司名

13. Avoid fully qualified type names. Use the using statement instead. 不要直接使用带命名空间的完整类型名称。使用using语句引用。

14. Avoid putting a using statement inside a namespace. 不要将using语句放到命名空间里面

15. Group all framework namespaces together and put custom or third-party namespaces underneath. 将引用的framework的命名空间组合排放,自定义的和第三方的命名空间放到最下面

16. Use delegate inference instead of explicit delegate instantiation使用委托定义而不是直接的委托实例。

delegate void SomeDelegate();

public void SomeMethod()

{...}

SomeDelegate someDelegate = SomeMethod;

17. Maintain strict indentation. Do not use tabs or nonstandard indentation, such as one space. Recommended values are three or four spaces, and the value should be uniform across. 严格使用缩进。不要使用tabs或非标准缩进,如单个空格。推荐使用3个或4个空格,这个值应该统一。

18. Indent comments at the same level of indentation as the code you are documenting. 注释与代码缩进相等。

19. All comments should pass spell checking. Misspelled comments indicate sloppy development. 所有的注释应该通过拼写检查。错误的拼写意味着垃圾的开发。

20. All member variables should be declared at the top, with one line separating them from the properties or methods. 所有的成员变量应该在顶部定义,与属性和方法使用一个空行隔开。

public class MyClass

{

int m_Number;

string m_Name;

public void SomeMethod1()

{ }

public void SomeMethod2()

{ }

}

21. Declare a local variable as close as possible to its first use. 局部变量的定义尽量靠近第一次被使用的地方。

22. A file name should reflect the class it contains. 文件名应该体现它包含的类(即类名与文件名统一)。

23. When using partial types and allocating a part per file, name each file after the logical part that part plays. For example: 当使用partial类时,包含每个部分的文件名应包含这个部分的逻辑含义。

//In MyClass.cs

public partial class MyClass

{...}

//In MyClass.Designer.cs

public partial class MyClass

{...}

24. Always place an open curly brace ({) in a new line. 总是将大括号({)放到新的一行里。

25. With anonymous methods, mimic the code layout of a regular method, aligned with the delegate declaration. (complies with placing an open curly brace in a new line): 使用匿名方法时,代码风格应该和普通方法一样,与委托声明对齐。(大括号应该放到新的一行里):

delegate void SomeDelegate(string someString);

//正确:

void InvokeMethod()

{

SomeDelegate someDelegate = delegate(string name)

{

MessageBox.Show(name);

};

someDelegate("Juval");

}

//避免

void InvokeMethod()

{

SomeDelegate someDelegate = delegate(string name){MessageBox.Show(name);};

someDelegate("Juval");

}

26. Use empty parentheses on parameter-less anonymous methods. Omit the parentheses only if the anonymous method could have been used on any delegate: 没有参数的匿名方法加上空的圆括号。除非这个匿名方法可能被用到任何类型的委托上。

delegate void SomeDelegate();

//正确

SomeDelegate someDelegate1 = delegate()

{

MessageBox.Show("Hello");

};

//避免

SomeDelegate someDelegate1 = delegate

{

MessageBox.Show("Hello");

};

27. With Lambda expressions, mimic the code layout of a regular method, aligned with the delegate declaration. Omit the variable type and rely on type inference, yet use parentheses: 使用Lambda表达式时,代码风格应该和普通方法一样,与委托声明对齐。省略变量类型,使用圆括号:

delegate void SomeDelegate(string someString);

SomeDelegate someDelegate = (name)=>

{

Trace.WriteLine(name);

MessageBox.Show(name);

};

28. Only use in-line Lambda expressions when they contain a single simple statement. Avoid multiple statements that require a curly brace or a return statement with inline expressions. Omit parentheses: 仅当Lambda表达式只包含一行简单语句的时候使用内嵌的风格。当包含多个语句和return语句的时候,不要使用内嵌的风格。省略圆括号:

delegate void SomeDelegate(string someString);

void MyMethod(SomeDelegate someDelegate)

{...}

//Correct:

MyMethod(name=>MessageBox.Show(name));

//Avoid

MyMethod((name)=>{Trace.WriteLine(name);MessageBox.Show(name);});

2. Coding Practices 编码实践

1. Avoid putting multiple classes in a single file. 不要将多个类放到一个文件中。

2. A single file should contribute types to only a single namespace. Avoid having multiple namespaces in the same file. 一个文件中应该只包含一个命名空间,不要同一文件包含多个命名空间。

3. Avoid files with more than 500 lines (excluding machine-generated code). 避免文件大小超过500行,除非是机器生成的代码

4. Avoid methods with more than 200 lines. 避免方法超过200行。

5. Avoid methods with more than 5 arguments. Use structures for passing multiple arguments. 避免方法有超过5个参数,否者使用结构来传递多个参数。

6. Lines should not exceed 120 characters. 每行应该不超过120个字符。

7. Do not manually edit any machine-generated code. 不要手工修改机器生成的代码。

a) If modifying machine generated code, modify the format and style to match this coding standard. 如果修改机器生成的代码,那代码风格应该遵从代码规范。

b) Use partial classes whenever possible to factor out the maintained portions. 尽量使用 partial 类来维护修改的代码。

8. Avoid comments that explain the obvious. Code should be self-explanatory. Good code with readable variable and method names should not require comments. 不要对显而易见的逻辑增加注释。代码应该是自解释的。好的代码使用好的变量名和方法名而不需要注释。

9. Document only operational assumptions, algorithm insights and so on. 仅对算法、假设等进行文档化。

10. Avoid method-level documentation. 避免方法级的文档。

a) Use extensive external documentation for API documentation. 对API文档使用外部文件。

b) Use method-level comments only as tool tips for other developers. 方法级上的注释只用作给其他开发人员的提示。

11. With the exception of zero and one, never hard-code a numeric value; always declare a constant instead. 除了0和1外,不要硬编码任何数字,总是使用常量代替。

12. Use the const directive only on natural constants such as the number of days of the week. 只对自然存在的数字,比如一个星期的天数等使用 const 关键字。

13. Avoid using const on read-only variables. For that, use the readonly directive. 只读的变量不要定义为 const,使用 readonly 关键字。

public class MyClass

{

public const int DaysInWeek = 7;

public readonly int Number;

public MyClass(int someValue)

{

Number = someValue;

}

}

14. Assert every assumption. On average, every fifth line is an assertion. 对所有假设使用断言。一般来说,每15行代码应该有一个断言。

using System.Diagnostics;

object GetObject()

{...}

object someObject = GetObject();

Debug.Assert(someObject != null);

15. Every line of code should be walked through in a “white box” testing manner. 每一行代码都应该被白盒测试覆盖。

16. Catch only exceptions for which you have explicit handling. 只捕捉要显式处理的异常。

17. In a catch statement that throws an exception, always throw the original exception (or another exception constructed from the original exception) to maintain the stack location of the original error: 在 catch 语句中抛出异常时,总是抛出原始异常(或从原始异常中构造出的其他异常)来维护错误堆栈中的位置:

catch(Exception exception)

{

MessageBox.Show(exception.Message);

throw;

}

18. Avoid error codes as method return values. 避免使用错误代码作为方法的返回值。

19. Avoid defining custom exception classes. 避免使用自定义的异常类。

20. When defining custom exceptions: 当自定义异常时:

a) Derive the custom exception from Exception. 自定义的异常类应该继承 Exception 类。

b) Provide custom serialization. 提供自定义的串行化。

21. Avoid multiple Main() methods in a single assembly. 在一个项目中避免出现多个 Main() 方法

22. Make only the most necessary types public, mark others as internal. 只公开必要的类型,对其他类型标记为 internal 。

23. Avoid friend assemblies, as they increase inter-assembly coupling. 避免 friend程序集,这样会增加程序集引用。

24. Avoid code that relies on an assembly running from a particular location. 避免代码依赖于特定位置运行的程序集。

25. Minimize code in application assemblies (EXE client assemblies). Use class libraries instead to contain business logic. 最小化可执行程序集(EXE 文件程序集)的代码。把逻辑都放到单独的类库中。

26. Avoid providing explicit values for enums unless they are integer powers of 2: 避免显式指定枚举值的数值,除非它们是2的指数:

//正确

public enum Co

{

Red, Green, B

}

//避免

public enum Co

{

Red = 1,

Green = 2,

Blue = 3

}

27. Avoid specifying a type for an enum. 避免使用指定类型的枚举类型。

//避免

public enum Color : long

{

Red, Green, Blue

}

28. Always use a curly brace scope in an if statement, even if it conditions a single statement. 就算 if 块中只有一个语句也使用大括号。

29. Avoid using the ternary conditional operator. 避免使用3元条件运算符。

30. Avoid explicit code exclusion of method calls (#if…#endif). Use conditional methods instead: 避免显式使用编译器条件指令(#if…#endif)。使用带条件标记的方法:

[Conditional("MySpecialCondition")]

public void MyMethod()

{}

31. Avoid function calls in Boolean conditional statements. Assign into local variables and check on them. 避免在条件中直接调用返回布尔值的函数。把返回值赋值给一个局部变量来使用。

bool IsEverythingOK()

{...}

//避免:

if(IsEverythingOK())

{...}

//正确:

bool ok = IsEverythingOK();

if(ok)

{...}

32. Always use zero-based arrays. 使用0为开始索引的数据。

33. With indexed collection, use zero-based indexes有索引的集合使用0开始的索引。

34. Always explicitly initialize an array of reference types using a for loop. 总是用 for 循环显式初始化引用类型的数组。

public class MyClass

{}

const int ArraySize = 100;

MyClass[] array = new MyClass[ArraySize];

for(int index = 0; index < array.Length; index++)

{

array[index] = new MyClass();

}

35. Do not provide public or protected member variables. Use properties instead. 不要使用公开的或保护的类成员变量,使用属性。

36. Avoid explicit properties that do nothing except access a member variable. Use automatic properties instead: 尽量使用自动属性。

//避免:

class MyClass

{

int m_Number;

public int Number

{

get

{

return m_Number;

}

set

{

m_Number = value;

}

}

}

//正确:

class MyClass

{

public int Number

{

get;

set;

}

}

37. Avoid using the new inheritance qualifier. Use override instead. 避免使用 new 继承关键字,使用 override 。

38. Always mark public and protected methods as virtual in a non-sealed class. 对于非密封类,公开和保护的方法总是标记为 virtual 。

39. Never use unsafe code, except when using interop. 除了 interop 外,决不使用使用 unsafe 代码。

40. Avoid explicit casting. Use the as operator to defensively cast to a type. 避免使用显式类型转换。使用 as 操作符做类型转换。

Dog dog = new GermanShepherd();

GermanShepherd shepherd = dog as GermanShepherd;

if(shepherd != null)

{...}

41. Always check a delegate for null before invoking it. 调用委托前总是判断它是否为空。

42. Do not provide public event member variables. Use event accessors instead. 不要公开事件成员变量。使用事件访问器来公开。

public class MyPublisher

{

MyDelegate m_SomeEvent;

public event MyDelegate SomeEvent

{

add

{

m_SomeEvent += value;

}

remove

{

m_SomeEvent -= value;

}

}

}

43. Avoid defining event-handling delegates. Use EventHandler<T> or GenericEventHandler instead. GenericEventHandler is defined in Chapter 6 of Programming .NET Components 2nd Edition. 避免定义 event-handling 委托。使用 EventHandler<T> 或者 GenericEventHandler 。GenericEventHandler 的定义请参考 《Programming .NET Components 2nd Edition》 第6章。

44. Avoid raising events explicitly. Use EventsHelper to publish events defensively. EventsHelper is presented in Chapter 6-8 of Programming .NET Components 2nd Edition. 避免显式引发事件。使用 EventsHelper 来引发事件。EventsHelper 的定义请参考《Programming .NET Components 2nd Edition》 第6-8章。

45. Always use interfaces. See Chapters 1 and 3 in Programming .NET Components 2nd Edition. 尽量使用接口。参见《Programming .NET Components 2nd Edition》第1-3章。

46. Classes and interfaces should have at least 2:1 ratio of methods to properties. 类和接口中方法和属性的比例应至少为 2:1

47. Avoid interfaces with one member. 避免空接口。

48. Strive to have three to five members per interface. 力求每个接口有3到5个成员。

49. Do not have more than 20 members per interface. Twelve is probably the practical limit. 接口不应有超过20个成员。一般来说不会超过12个。

50. Avoid events as interface members. 避免在接口中声明事件。

51. When using abstract classes, offer an interface as well. 定义抽象类时同时定义一个接口。

52. Expose interfaces on class hierarchies. 暴露接口的类层次结构

53. Prefer using explicit interface implementation. 推荐使用显示的接口实现。

54. Never assume a type supports an interface. Defensively query for that interface. 不要假设一个类型实现了一个接口。

SomeType obj1;

IMyInterface obj2;

/*初始化 obj1:*/

obj2 = obj1 as IMyInterface;

if(obj2 != null)

{

obj2.Method1();

}

else

{

//处理错误

}

55. Never hardcode strings that will be presented to end users. Use resources instead. 不要硬编码要显示给用户的字符串。使用资源。

56. Never hardcode strings that might change based on deployment such as connection strings. 不要硬编码部署相关的字符串比如数据库连接字符串。

57. Use String.Empty instead of "":不要使用 "" ,使用 String.Empty 。

//避免

string name = "";

//正确

string name = String.Empty;

58. When building a long string, use StringBuilder, not string. 处理长字符串时,使用 StringBuilder 而不是直接使用 string。

59. Avoid providing methods on structures. 避免在结构里包含方法。

a) Parameterized constructors are encouraged. 尽量使用带参数的构造方法。

b) Can overload operators. 可以重载操作符。

60. Always provide a static constructor when providing static member variables. 当有静态成员时,总是定义一个静态构造函数。

61. Do not use late-binding invocation when early-binding is possible. 当可以使用前期绑定时不要使用后期绑定。

62. Use application logging and tracing. 使用日志和跟踪。

63. Never use goto unless in a switch statement fall-through. 除了在 switch 块中,不要使用 goto 语句。

64. Always have a default case in a switch statement that asserts. 在 switch 中总是加入 default 分支。

int number = SomeMethod();

switch(number)

{

case 1:

Trace.WriteLine("Case 1:");

break;

case 2:

Trace.WriteLine("Case 2:");

break;

default:

Debug.Assert(false);

break;

}

65. Do not use the this reference unless invoking another constructor from within a constructor. 除非是调用另一个构造方法,不要使用 this 限定符。

//使用 this 限定符的例子

public class MyClass

{

public MyClass(string message)

{ }

public MyClass()

: this("Hello")

{ }

}

66. Do not use the base word to access base class members unless you wish to resolve a conflict with a subclasses member of the same name or when invoking a base class constructor. 不要使用 base 限定符去访问基类成员,除非子类中有重写了这个成员或调用基类的构造函数。

//使用 base限定符的例子

public class Dog

{

public Dog(string name)

{ }

virtual public void Bark(int howLong)

{ }

}

public class GermanShepherd : Dog

{

public GermanShepherd(string name)

: base(name)

{ }

override public void Bark(int howLong)

{

base.Bark(howLong);

}

}

67. Do not use GC.AddMemoryPressure().不要使用 GC.AddMemoryPressure()

68. Do not rely on HandleCollector. 不要依赖于 HandleCollector

69. Implement Dispose() and Finalize() methods based on the template in Chapter 4 of Programming .NET Components 2nd Edition. 实现 Dispose() 和 Finalize() 时,参考《Programming .NET Components 2nd Edition》 第4章的模板。

70. Always run code unchecked by default (for the sake of performance), but explicitly in checked mode for overflow- or underflow-prone operations: 总是在 unchecked 模式下运行代码,对需要检查溢出的地方显示声明 checked 。

int CalcPower(int number,int power)

{

int result = 1;

for(int count = 1;count <= power;count++)

{

checked

{

result *= number;

}

}

return result;

}

71. Avoid casting to and from System.Object in code that uses generics. Use constraints or the as operator instead: 当使用泛型时,避免将其他类型显示转换成 System.Object 从显示转换回其他类型。使用约束或 as 操作符:

class SomeClass

{ }

//避免:

class MyClass<T>

{

void SomeMethod(T t)

{

object temp = t;

SomeClass obj = (SomeClass)temp;

}

}

//正确:

class MyClass<T> where T : SomeClass

{

void SomeMethod(T t)

{

SomeClass obj = t;

}

}

72. Do not define constraints in generic interfaces. Interface-level constraints can often be replaced by strong-typing. 不要再使用泛型的接口上增加约束。接口上的约束应该用强类型来实现。

public class Customer

{...}

//避免:

public interface IList<T> where T : Customer

{...}

//正确:

public interface ICustomerList : IList<Customer>

{...}

73. Do not define method-specific constraints in interfaces. 接口里不要定义方法级的约束。

74. Do not define constraints in delegates. 委托上不要定义约束。

75. If a class or a method offers both generic and non generic flavors, always prefer using the generics flavor. 如果一个类或方法同时提供泛型和非泛型实现,总是选择使用泛型实现。

76. When implementing a generic interface that derives from an equivalent non-generic interface (such as IEnumerable<T>), use explicit interface implementation on all methods, and implement the non-generic methods by delegating to the generic ones: 当实现一个从非泛型接口上集成下来的带泛型的接口时(比如 IEnumerable<T>),在所有的方法上使用显示实现,对非泛型的方法的实现通过调用泛型实现来完成:

class MyCollection<T> : IEnumerable<T>

{

IEnumerator<T> IEnumerable<T>.GetEnumerator()

{...}

IEnumerator IEnumerable.GetEnumerator()

{

IEnumerable<T> enumerable = this;

return enumerable.GetEnumerator();

}

}

3. Project Settings and Project Structure 项目设置和项目结构

1. For Target Framework, always select the earliest target framework required for your solution, unlike the default which will give you the latest: 总是使用低版本的framework开发。

clip_image002

2. Always build your project with warning level 4总是以4级警告建立项目

clip_image004

3. Treat warnings as errors in the Release build (note that this is not the default of Visual Studio). Although it is optional, this standard recommends treating warnings as errors in Debug builds as well. 在发布版中将警告作为错误(注意这不是VS.NET的缺省设置)

clip_image006

4. Avoid suppressing specific compiler warnings. 永远不要抑制特定的编译警告

5. Always explicitly state your supported runtime versions in the application configuration file. 总是在应用程序的配置文件中显式地说明支持的运行时版本。参见Programming .NET Components第五章

<?xml version="1.0"?>

<configuration>

<startup>

<supportedRuntime version="v2.0.50727.0"/>

<supportedRuntime version="v1.1.4322.0"/>

</startup>

</configuration>

6. Avoid explicit custom version redirection and binding to CLR assemblies. 避免显式地自定义版本改向和绑定到CLR程序集。

7. Avoid explicit preprocessor definitions (#define). Use the project settings for defining conditional compilation constants. 避免显式的预编译定义(#define)。使用项目设置定义条件编译常量。

8. Do not put any logic inside AssemblyInfo.cs. 不要在AssemblyInfo.cs中放任何逻辑。

9. Do not put any assembly attributes in any file besides AssemblyInfo.cs. 除了在AssemblyInfo.cs,不要在任何文件中放程序集属性。

10. Populate all fields in AssemblyInfo.cs such as company name, description, and copyright notice. 在AssemblyInfo.cs中提供所有字段,例如公司名称、描述、版权等。

11. All assembly references in the same solution should use relative paths. 所有程序集应该使用相对路径引用。

12. Disallow cyclic references between assemblies. 不允许在程序集中循环引用。

13. Avoid multi-module assemblies. 避免多模块的程序集。

14. Avoid tampering with exception handling using the Exception window (Debug|Exceptions). 避免使用Exception窗口(Debug|Exceptions)篡改异常处理。

15. Strive to use uniform version numbers on all assemblies and clients in the same logical application (typically a solution). Use the SolutionInfo.cs technique from Chapter 5 of Programming .NET Components 2nd Edition to automate. 努力对同一逻辑应用程序中(通常是一个解决方案)的所有程序集和客户端使用统一的版本号。

16. Link all solution-wide information to a global shared SolutionInfo.cs file. 链接一个包含所有解决方案级信息的全局共享文件

17. Name your application configuration file as App.config, and include it in the project.应用程序的配置文件命名为App.config,并将其包括在项目中。

18. Modify Visual Studio 2008 default project structure to comply with your project standard layout, and apply uniform structure for project folders and files. 链接一个包含所有解决方案级信息的全局共享文件(图略)。

19. A Release build should contain debug symbols. 发布版中应该包含调试符号。

clip_image008

20. Always sign your assemblies, including the client applications. 总是对程序集签名,包括客户端应用程序。

21. Use password-protected keys. 使用密码包括keys。

4. Framework Specific Guideline Framework说明

4.1 Data Access数据访问

1. Always use type-safe datasets or data tables. Avoid raw ADO.NET.总是使用类型安全的data sets和data tables,避免使用原始ADO.NET。

2. Always use transactions when accessing a database.总是使用transactions访问数据库。

a) Always use WCF, Enterprise Services or System.Transactions transactions.总是使用WCF, Enterprise Services 或者 System.Transactions transactions.

b) Do not use ADO.NET transactions by enlisting the database explicitly.不要使用ADO.NET transactions。

3. Always use transaction isolation level set to Serializable. Management decision is required to use anything else. Do not use the Data Source window to drop connections on windows forms, ASP.NET forms or web services. Doing so couples the presentation tier to the data tier. 总是将事务隔离级别设置为Serializable。管理决策需要用别的东西.。不要使用Data Source窗口拖拽连接到windows forms, ASP.NET forms 或 web services。这样做会耦合显示层和数据层。

4. Avoid SQL Server authentication. Use Windows authentication instead.避免SQL Server验证,采用Windows验证代替。

5. Run components accessing SQL Server under separate identity from that of the calling client. 客户端使用组件访问SQL Server。

6. Always wrap your stored procedures in a high level, type safe class. Only that class invokes the stored procedures. Let Visual Studio 2008 type-safe data adapters automate as much of that as possible.

7. Avoid putting any logic inside a stored procedure. If you have anything more complex than simple switching logic to vary your query based on the parameter values, you should consider putting that logic in the business logic of the consuming code、

4.2 ASP.NET and Web Services

1. Avoid putting code in ASPX files of ASP.NET. All code should be in the code-beside partial class.

2. Code in code beside partial class of ASP.NET should call other components rather than contain direct business logic.

3. Always check a session variable for null before accessing it.

4. In transactional pages or web services, always store session in SQL server.

5. Avoid setting the Auto-Postback property of server controls in ASP.NET to True.

6. Turn on Smart Navigation for ASP.NET pages.

7. Strive to provide interfaces for web services. See Appendix A of Programming .NET Components 2nd Edition.

8. Always provide a namespace and service description for web services.

9. Always provide a description for web methods.

10. When adding a web service reference, provide a meaningful name for the location.

11. In both ASP.NET pages and web services, wrap a session variable in a local property. Only that property is allowed to access the session variable, and the rest of the code uses the property, not the session variable.

public class Calculator : WebService

{

int Memory

{

get

{

int memory = 0;

object state = Session["Memory"];

if (state != null)

{

memory = (int)state;

}

return memory;

}

set

{

Session["Memory"] = value;

}

}

[WebMethod(EnableSession = true)]

public void MemoryReset()

{

Memory = 0;

}

}

12. Always modify a client-side web service wrapper class to support cookies, since you have no way of knowing whether the service uses Session state or not.

public class Calculator : SoapHttpClientProtocol

{

public Calculator()

{

CookieContainer = new System.Net.CookieContainer();

Url = ...;

}

}

4.3 Multithreading

1. Use Synchronization Domains. See Chapter 8 in Programming .NET Components 2nd Edition. Avoid manual synchronization because that often leads to deadlocks and race conditions.

2. Never call outside your synchronization domain.

3. Manage asynchronous call completion on a callback method. Do not wait, poll, or block for completion.

4. Always name your threads. The name is traced in the debugger Threads window, making debug sessions more productive.

Thread currentThread = Thread.CurrentThread;

string threadName = "Main UI Thread";

currentThread.Name = threadName;

5. Do not call Suspend() or Resume() on a thread.

6. Do not call Thread.Sleep(), except in the following conditions:

a) Thread.Sleep(0) is an acceptable optimization technique to force a context switch.

b) Thread.Sleep() is acceptable in testing or simulation code.

7. Do not call Thread.SpinWait().

8. Do not call Thread.Abort() to terminate threads. Use a synchronization object instead to signal the thread to terminate. See Chapter 8 in Programming .NET Components 2nd Edition.

9. Avoid explicitly setting thread priority to control execution. You can set thread priority based on task semantic, such as below normal (ThreadPriority.BelowNormal) for a screen saver.

10. Do not read the value of the ThreadState property. Use Thread.IsAlive to determine whether the thread is dead or alive.

11. Do not rely on setting the thread type to background thread for application shutdown. Use a watchdog or other monitoring entity to deterministically kill threads.

12. Do not use thread local storage unless thread affinity is guaranteed.

13. Do not call Thread.MemoryBarrier().

14. Never call Thread.Join() without checking that you are not joining your own thread.

void WaitForThreadToDie(Thread thread)

{

Debug.Assert(Thread.CurrentThread.ManagedThreadId != thread.ManagedThreadId);

thread.Join();

}

15. Always use the lock() statement rather than explicit Monitor manipulation.

16. Always encapsulate the lock() statement inside the object it protects.

public class MyClass

{

public void DoSomething()

{

lock(this)

{...}

}

}

17. You can use synchronized methods instead of writing the lock() statement yourself.

18. Avoid fragmented locking (see Chapter 8 of Programming .NET Components 2nd Edition).

19. Avoid using a Monitor to wait or pulse objects. Use manual or auto-reset events instead.

20. Do not use volatile variables. Lock your object or fields instead to guarantee deterministic and thread-safe access. Do not use Thread.VolatileRead(), Thread.VolatileWrite(), or the volatile modifier.

21. Avoid increasing the maximum number of threads in the thread pool.

22. Never stack lock statements because that does not provide atomic locking. Use WaitHandle.WaitAll() instead.

MyClass obj1 = new MyClass();

MyClass obj2 = new MyClass();

MyClass obj3 = new MyClass();

//Do not stack lock statements

lock(obj1)

lock(obj2)

lock(obj3)

{

obj1.DoSomething();

obj2.DoSomething();

obj3.DoSomething();

}

4.4 Serialization

1. Prefer the binary formatter.

2. Mark serialization event handling methods as private.

3. Use the generic IGenericFormatter interface. See Chapter 9 of Programming .NET Components 2nd Edition.

4. Mark non-sealed classes as serializable.

5. When implementing IDeserializationCallback on a non-sealed class, make sure to do so in a way that allowed subclasses to call the base class implementation of OnDeserialization().See Chapter 3 of Programming .NET Components 2nd Edition.

6. Always mark un-serializable member variables as non serializable.

7. Always mark delegates on a serialized class as non-serializable fields:

[Serializable]

public class MyClass

{

[field: NonSerialized]

public event EventHandler MyEvent;

}

4.5 Remoting

1. Prefer administrative configuration to programmatic configuration.

2. Always implement IDisposable on single call objects.

3. Always prefer a TCP channel and a binary format when using remoting, unless a firewall is present.

4. Always provide a null lease for a singleton object.

public class MySingleton : MarshalByRefObject

{

public override object InitializeLifetimeService()

{

return null;

}

}

5. Always provide a sponsor for a client activated object. The sponsor should return the initial lease time.

6. Always unregister the sponsor on client application shutdown.

7. Always put remote objects in class libraries.

8. Avoid using SoapSuds.

9. Avoid hosting in IIS.

10. Avoid using uni-directional channels.

11. Always load a remoting configuration file in Main() even if the file is empty, and the application does not use remoting.

static void Main()

{

RemotingConfiguration.Configure("MyApp.exe.config");

/* Rest of Main() */

}

12. Avoid using Activator.GetObject() and Activator.CreateInstance() for remote objects activation. Use new instead.

13. Always register port 0 on the client side, to allow callbacks.

14. Always elevate type filtering to full on both client and host to allow callbacks.

4.6 Security

1. Always demand your own strong name on assemblies and components that are private to the application, but are public (so that only you can use them).

public const string MyCompany = "1234567894800000940000000602000000240000"+

"52534131000400000100010007D1FA57C4AED9F0"+

"A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C83"+

"4C99921EB23BE79AD9D5DCC1DD9AD23613210290"+

"0B723CF980957FC4E177108FC607774F29E8320E"+

"92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99"+

"285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF"+

"0FC4963D261C8A12436518206DC093344D5AD293";

}

[StrongNameIdentityPermission(SecurityAction.LinkDemand,

PublicKey = PublicKeys.MyCompany)]

public class MyClass

{...}

2. Apply encryption and security protection on application configuration files.

3. When importing an interop method, assert unmanaged code permission, and demand appropriate permission instead.

public class PublicKeys

{

[DllImport("user32",EntryPoint="MessageBoxA")]

private static extern int Show(IntPtr handle,string text,string caption,

int msgType);

[SecurityPermission(SecurityAction.Assert,UnmanagedCode = true)]

[UIPermission(SecurityAction.Demand,

Window = UIPermissionWindow.SafeTopLevelWindows)] www.idesign.net January 2008

public static void Show(string text,string caption)

{

Show(IntPtr.Zero,text,caption,0);

}

}

4. Do not suppress unmanaged code access via the SuppressUnmanagedCodeSecurity attribute.

5. Do not use the /unsafe switch of TlbImp.exe. Wrap the RCW in managed code so that you could assert and demand permissions declaratively on the wrapper.

6. On server machines, deploy a code access security policy that grants only Microsoft, ECMA, and self (identified by a strong name) full trust. Code originating from anywhere else is implicitly granted nothing.

7. On client machines, deploy a security policy which grants client application only the permissions to execute, to call back the server and to potentially display user interface. When not using ClickOnce, client application should be identified by a strong name in the code groups.

8. To counter a luring attack, always refuse at the assembly level all permissions not required to perform the task at hand.

[assembly:UIPermission(SecurityAction.RequestRefuse, Window=UIPermissionWindow.AllWindows)]

9. Always set the principal policy in every Main() method to Windows

public class MyClass

{

static void Main()

{

AppDomain currentDomain = Thread.GetDomain();

currentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

}

//other methods

}

10. Never assert a permission without demanding a different permission in its place. See Chapter 12 in Programming .NET Components 2nd Edition.

4.7 System.Transactions

1. Always dispose of a TransactionScope object.总是销毁TransactionScope对象。

2. Inside a transaction scope, do not put any code after the call to Complete().不要在Complete()后添加任何代码。

3. When setting the ambient transaction, always save the old ambient transaction and restore it when you are done.

4. In Release builds, never set the transaction timeout to zero (infinite timeout).

5. When cloning a transaction, always use DependentCloneOption.BlockCommitUntilComplete.

6. Create a new dependent clone for each worker thread. Never pass the same dependent clone to multiple threads.

7. Do not pass a transaction clone to the TransactionScope's constructor.

8. Always catch and discard exceptions thrown by a transaction scope that is set to TransactionScopeOption.Suppress.

4.8 Enterprise Services

1. Do not catch exceptions in a transactional method. Use the AutoComplete attribute. See Chapter 4 in COM and .NET Component Services.

2. Do not call SetComplete(), SetAbort(), and the like. Use the AutoComplete attribute.

[Transaction]

public class MyComponent : ServicedComponent

{

[AutoComplete]

public void MyMethod(long objectIdentifier)

{...}

}

3. Always override CanBePooled and return true (unless you have a good reason not to return to pool)

public class MyComponent : ServicedComponent

{

protected override bool CanBePooled()

{

return true;

}

}

4. Always call Dispose() explicitly on a pooled objects unless the component is configured to use JITA as well.

5. Never call Dispose() when the component uses JITA.

6. Always set authorization level to application and component.

7. Set authentication level to privacy on all applications.

[assembly: ApplicationActivation(ActivationOption.Server)]

[assembly: ApplicationAccessControl(

true, //Authorization

AccessChecksLevel=AccessChecksLevelOption.ApplicationComponent,

Authentication=AuthenticationOption.Privacy,

ImpersonationLevel=ImpersonationLevelOption.Identify)]

8. Set impersonation level on client assemblies to Identity.

9. Always set ComponentAccessControl attribute on serviced components to true (the default is true)

[ComponentAccessControl]

public class MyComponent : ServicedComponent

{...}

10. Always add to the Marshaler role the Everyone user

[assembly: SecurityRole("Marshaler",SetEveryoneAccess = true)]

11. Apply SecureMethod attribute to all classes requiring authentication.

[SecureMethod]

public class MyComponent : ServicedComponent

{...}

posted @ 2009-09-15 17:20  流泉飞石  阅读(1543)  评论(0编辑  收藏  举报