微智科技网
您的当前位置:首页Cshorp编码规范

Cshorp编码规范

来源:微智科技网
Cshorp编码规范Version

一、命名规则和风格

1.使用Pascal casing命名规则来命名方法名称和常量,这种格式的特点是方法中每个单词的第1个字母都是大写,而其他字母是小写:

public class SomeClass {

const int DefaultSize = 100; public void SomeMethod()

}

{}

2.使用camel casing命名规则来命名局部变量名和方法的参数,camel casing与P

ascal casing差不多,但前者第一个字母不需要大写:

void MyMethod(int someNumber) {

int number; }

3.接口的命名规则在遵守Pascal casing规则的同时加前缀I:

interface IMyInterface {...}

4.私有变量在遵守Pascal casing规则的同时加前缀m_:

public class SomeClass {

private int m_Number; }

5.自定义属性类名采用Attribute作为后缀 6.自定义异常类名采用Exception作为后缀 7.采用动词-对象对命名方法,例如ShowDialog()

8.有返回值的方法应该取名表示其返回值,例如GetObjectState() 9.采用描述性的变量名。

a)避免采用单字母的变量名,如i或t;而是采用index或temp。 b)对public和protected成员避免采用用匈牙利命名法。 c)不要采用缩写(例如将number缩写为num)。

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

object不用Object,采用string不用String,采用int不用Int32。

11.对于泛型,类型采用大写字母。当处理.NET类型Type时保留后缀Type。

//正确:

public class LinkedList {...}

//避免: public class LinkedList {...}

12.采用有意义的命名空间名,例如产品名称或公司名称。 13.避免使用类的全称,而是采用using语句。 14.避免在命名空间里声明using。

15.将所有Framework命名空间名放在一起,后面放自定义或第三方的命名空间名。

using System;

using System.Collections.Generic; using System.ComponentModel;

using System.Data;

using MyCompany;

using MyControls;

16.采用委托推断,不要显式实例化委托

delegate void SomeDelegate();

public void SomeMethod() {...}

SomeDelegate someDelegate = SomeMethod;

17.严格遵守缩进格式。不用采用tab或非标准的缩进,如1个空格。被推荐的缩进采

用3个或4个空格。而且这些缩进必须统一。

18.注释缩进和其注释的代码在同一层次。

19.所有注释要经过拼写检查。拼写错误的注释表明开发的草率。 20.所有成员变量应该定义在前面,和属性或方法间空开一行。

public class MyClass {

int m_Number; string m_Name;

public void SomeMethod1() {}

public void SomeMethod2() {} }

21.局部变量的定义尽可能靠近它的初次使用的地方。 22.文件名应该体现其包含的类。

23.当使用partial类型且每部分分配一个文件时,以类型名加P和序数命名每个文件

//In MyClass.cs

public partial class MyClass {...}

//In MyClass.Designer.cs public partial class MyClass {...}

24.左大括号总是放在新行中。

25.匿名方法仿照普通方法的布局,和匿名委托定义放在一行。

delegate void SomeDelegate(string someString); //正确使用

void InvokeMethod() {

SomeDelegate someDelegate = delegate(string name)

{

}

someDelegate(\"Juval\"); MessageBox.Show(name); }; //避免使用

void InvokeMethod() {

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

26.没有参数的匿名方法使用空括号。仅当匿名方法可能被用于任何委托时省略括号。

delegate void SomeDelegate();

//正确使用 SomeDelegate someDelegate1 = delegate()

{ //避免使用

MessageBox.Show(\"Hello\");

};

SomeDelegate someDelegate1 = delegate

{

MessageBox.Show(\"Hello\"); };

27.根据LAMBDA的表现形式,模仿标准方法的代码的布局,就好像委托的声明一样。省略变量类型和预测的类型,但使用圆括号:

delegate void SomeDelegate(string someString);

SomeDelegate someDelegate = (name)=>

{

Trace.WriteLine

(name); MessageBox.Show(name); };

28.当包含一个单一的简单的声明的时候,仅仅使用一致的LAMBDA表达式,避免多重声明,要求,或return语句与一致的表达式。省略括号

delegate void SomeDelegate(string someString);

void MyMethod(SomeDelegate someDelegate) {...} //正确使用:

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

//避免使用:

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

二、编码实践

1.避免在一个文件中放多个类。

2.一个文件应该只对一个命名空间提供类型。避免在同一文件中有多个命名空间。 3.避免文件长度超过500行.(除了电脑自动生成的代码) 4.避免一个方法的定义超过200行。

5.避免超过5个参数的方法。使用结构传递多个参数。 6.避免单个行的字符超过120个。 7.不要手工编辑任何机器自动生成的代码。

a)如果修改机器自动生成的代码,修改后的格式和风格必须与本规范相一致。 b)尽可能采用不完全类(partial classes )来分离出需要维护的部分

8.避免对显而易见的内容做注释,代码应该是自解释的,由可读性强的变量和方法组成的好的代码应该不需要注释。

9.仅对操作的前提,内在算法等等撰写文档。 10.避免方法级的文档:

a)对API文档采用大量的外部文档。

b)方法级别的注释仅仅是对其他开发人员的提示。

11.除了数字0和1以外,避免使用硬编码数值,而是声明一个常量来替代它。 12.仅仅对本来就是常量的值使用const修饰符,例如一个星期的天数。 13.避免对只读变量使用const修饰符,在这种情况下,使用readonly修饰符:

public class MyClass {

public const int DaysInWeek = 7; public readonly int Number; public MyClass(int someValue) {

Number = someValue; } }

14.对任何假设采用断言,平均地,每5行中就有一行是断言。

using System.Diagnostics;

object GetObject() {...}

object someObject = GetObject(); Debug.Assert(someObject != null);

15.每行代码都要经过白盒测试。 16.仅仅catch你已经处理了的异常。

17.在抛出异常的catch语句中,总是抛出最初异常(或者是由最初异常引发的异常)

以保持最初错误的堆栈位置。

catch(Exception exception) {

MessageBox.Show(exception.Message); throw; }

18.避免将错误代码作为方法的返回值。 19.避免定义自定义的异常处理类。 20.当定义自定义的异常处理类时:

a)自定义的异常处理类必须从Exception继承而来 b)提供自定义的序列化

21.避免在一个程序集中使用多个mian()函数。

22.仅对最需要的类型使用public,其他的都使用internal。

23.避免使用friend程序集,这样回增加程序集之间的耦合性。 24.避免使用依赖运行的程序集的代码。

25.将应用程序集(exe文件)中的代码减少到最少,采用类库来代替业务逻辑层代码。 26.避免对枚举提供确切的值除非它是整数的2次幂:

//正确使用

public enum Color

{

Red,Green,Blue }

//避免使用

public enum Color {

Red

}

= 1, Green = 2, Blue = 3

27.避免对枚举指定具体类型:

//避免使用

public enum Color : long {

Red,Green,Blue }

28.if语句总是使用括号,即使它只有一条语句。 29.避免使用三元运算符。

30.避免明确的代码排除方法调用(#if… #endif )。而是有条件的使用方法:

[Conditional(\"MySpecialCondition\")] public void MyMethod() {}

31.避免在布尔条件语句中调用函数。赋值到局部变量并检查它们的值。

bool IsEverythingOK() {...} //避免使用:

if(IsEverythingOK()) {...} //正确使用:

bool ok = IsEverythingOK(); if(ok) {...}

32.总是使用从0开始的数组。

33.在一个索引集合中,使用从0开始的索引。

34.总是使用一个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.不用提供public或protected成员变量,而是使用属性。

36.避免什么也不做,除了存取成员变量的明确的属性,而是使用自动的属性:

//避免使用: class MyClass {

int m_Number;

public int Number {

get {

} set {

return m_Number;

m_Number = value; } } }

//正确使用: class MyClass

{

public int Number {

get;set; } }

37.避免使用new继承修饰符,而是使用override。

38.对非密封类总是将public和protected方法标记为virtual。 39.除非涉及到互操作,永远不要用不安全的代码。 40.避免显式类型转换。使用as算法防护性地转换类型。

Dog dog = new GermanShepherd(); GermanShepherd shepherd = dog as GermanShepherd; if(shepherd != null) {...}

41.总是在条用委托之前,检查它是否为空。

42.不要提供public的事件成员变量,而是使用事件访问器。

public class MyPublisher {

MyDelegate m_SomeEvent;

public event MyDelegate SomeEvent {

add {

m_SomeEvent += value; } remove {

m_SomeEvent -= value; } } }

43.避免定义事件处理的委托。使用eventhandler 或genericeventhandler来

代替。

44.使用Programming .net Components中定义的EventsHelper类安全地发布事件。

45.总是使用接口。

46.类和接口中方法和属性的比例至少是2:1。 47.避免使用一个接口的成员。 48.努力使一个接口拥有3-4个成员。

49.每个接口不应该超过20成员,12个可能已经是实际应用中的最大了。 50.避免事件作为接口的成员。

51.当使用抽象方法的时候,最好是用接口来代替。 52.在类的层次结构中暴露接口。 53.最好使用明确的接口来实现。

54.永远不要假设一种类型支持某个接口。防护性地检查是否支持该接口。

SomeType obj1; IMyInterface obj2;

/* Some code to initialize obj1, then: */ obj2 = obj1 as IMyInterface; if(obj2 != null) {

obj2.Method1();

} else {

//Handle error in expected interface }

55.出现在用户面前的字符串永远不用硬编码,而是使用资源来代替。 56.可能修改的字符串永远不用硬编码,例如连接字符串。 57.使用string.Empty来代替空字符串\"\":

//避免使用

string name = \"\";

//正确使用

string name = String.Empty;

58.构建一个长字符串的,尽量使用StringBuilder,而不是string。 59.避免提供带结构的方法:

a)参数化的构造函数是鼓励使用的。 b)可以重载算符。

60.当提供静态成员变量时,总是提供一个静态构造函数。 61.只要可以用前期绑定就不要用后期绑定。 62.对应用程序进行日志和跟踪。

63.除非在switch语句中跳转,永远不要用goto语句。 .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.除非在构造函数中调用另一个构造函数,否则不使用this。

//Example of proper use of ’this’ public class MyClass {

public MyClass(string message) {}

public MyClass() : this(\"Hello\") {} }

66.除非为了解决调用基类构造函数时成员名的冲突,否则不要使用base访问基类的

成员。

//Example of proper use of ’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.不要使用GC.AddMemoryPressure().(通知运行库在安排垃圾回收时应考虑分配大量的非托管内存)

68.不依赖handleCollector。跟踪未处理的句柄,并在达到指定阈值时强制执行垃圾回收。

69.根据Programming .NET Components第四章中的模板实现Dispose()和Finalize()方法。

70.缺省总是以非检查的方式运行(为了性能考虑),但是对易于溢出或下溢的操作显式使用检查模式:

int CalcPower(int number,int power) {

int result = 1;

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

checked {

result *= number; } }

return result; }

71.使用泛型的代码中避免与System.Object进行类型转换,而是使用或as算符。

class SomeClass {} //Avoid:

class MyClass {

void SomeMethod(T t) {

object temp = t;

SomeClass obj = (SomeClass)temp; } }

//Correct:

class MyClass where T : SomeClass {

void SomeMethod(T t) {

SomeClass obj = t; } }

72.泛型接口不要定义。接口层的通常能用强类型代替。

public class Customer {...} //Avoid:

public interface IList where T : Customer {...} //Correct:

public interface ICustomerList : IList {...}

73.不要在接口中定义与方法相关的。 74.不要在委托中定义。

75.如果一个类或一个方法提供通用和不通用的接口,总是使用通用的接口。 76.当实现一个来自于一个相等于非通用的接口(如IEnumerable)的一个通用接

口,对所有方法使用明确的接口,并实现有关的非通用接口的方法。

class MyCollection : IEnumerable {

IEnumerator IEnumerable.GetEnumerator() {...}

IEnumerator IEnumerable.GetEnumerator() {

IEnumerable enumerable = this;

return enumerable.GetEnumerator(); } }

三、项目设置和项目结构

1.对于目标的框架,始终选择最早的目标框架所需的解决方案,不同的预设,这将给你

最新消息:

2.总是以4级警告建立项目。

3.在发布版中将警告作为错误(注意这不是VS.net的缺省设置),虽然是可选的,本标准也推荐在调试版中将警告作为错误。

4.永远不要禁止特定的编译警告。

5.总是在应用程序的配置文件中显式地说明支持的运行时版本。

6.避免显式地自定义版本改向和绑定到CLR程序集。

7.避免显式的预编译定义(#define)。使用项目设置定义条件编译常量。 8.不要在AssemblyInfo.cs中放任何逻辑。

9.除了在AssemblyInfo.cs,不要在任何文件中放程序集属性。

10.在AssemblyInfo.cs中提供所有字段,例如公司名称、描述、版权等。 11.所有程序集应该使用相对路径引用。 12.不允许在程序集中循环引用。 13.避免多模块的程序集。

14.避免使用Exception窗口(Debug|Exceptions)篡改异常处理。

15.努力对同一逻辑应用程序中(通常是一个解决方案)的所有程序集和客户端使用统

一的版本号。

16.链接一个包含所有解决方案级信息的全局共享文件。

17.应用程序的配置文件命名为App.config,并将其包括在项目中。

18.将Visual Studio 2008缺省的项目结构改为标准的布局,对项目文件夹和文件应用统一的结构。

19.一个发布的版本中应该包含调试符号。 20.总是对程序集签名,包括客户端应用程序。 21.使用口令密码。

四、Framework特别指导 4.1 数据访问

1.总是使用类型安全的数据集或者数据表。避免使用原始的ADO.NET。 2.访问数据库时总是使用事务。

a)始终使用WCF,服务组件,System.Transactions等处理事务。

通信基础(Windows Communication Foundation,WCF)是基于Windows

平台下开发和部署服务的软件开发包(Software Development Kit,SDK)。WCF为服务提供了运行时环境(Runtime Environment),使得开发者能够将CLR类型公开为服务,又能够以CLR类型的方式使用服务。理论上讲,创建服务并不一定需要WCF,但实际上,使用WCF却可以使得创建服务的任务事半功倍。WCF是微软对一系列产业标准定义的实现,包括服务交互、类型转换、封送(Marshaling)以及各种协议的管理。

使用 System.Transactions 命名空间包含的类可以编写自己的事务应用程序和资源管理器。具体地说,可以创建和参与(与一个或多个参与者)本地或分布式事务。

b)不要使用ADO.NET事务来显示的支持数据库。

3.总是将事务隔离级别设置为序列的。使用其它隔离级别需要管理层决定。 4.不要使用数据源浏览器将数据库连接拖到Windows表单、ASP.NET表单或Web服务中。这样做耦合了界面层和数据层。

5.避免使用SQL Server验证。而是使用Windows验证。

6.将访问SQL Server的组件以调用该组件客户端不同的身份运行。 7.总是在高层用类型安全的类包装存储过程。仅在那个类中调用存储过程。 8.避免在存储过程中放任何逻辑。你应该考虑把这一逻辑放在业务逻辑层上。

Windows

4.2 ASP.NET和Web服务

1.避免把代码放到ASP.NET中的ASPX文件中去,所有的代码应该放在不完全类中。 2.尽量把代码放到ASP.NET中的不完全类中。 3.总是在使用session变量之前检查它是否是空。

4.在处理事务的页面或者web服务中,总是把session值放到sqlserver数据库中。

5.避免设置服务器控件的AutoPostback属性为true。 6.打开ASP.NET页面的智能导航。 7.努力为web服务提供接口。

8.总是为web服务提供一个命名控件和服务描述。 9.总是为一个web方法提供描述。

10.当添加一个web服务的参考时,对这个位置应该提供一个有意思的名称。 11.在ASPX.NET页面和web服务中,把访问session变量的权限赋予所有者,仅仅所有者被允许访问这个session变量,其它就不能使用这个session变量。

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.总是修改客户端的web服务包装类去支持cookies,因为你无从得知服务所使用

的会话状态。

public class Calculator : SoapHttpClientProtocol {

public Calculator() {

CookieContainer = new System.Net.CookieContainer(); Url = ...; } }

4.3 多线程

1.应用同步机制空间。避免手动同步,这样会造成死锁和紊乱。 2.不要在同步域外面调用你的同步机制空间。

3.用回调方法控制非同步调用,不要等待,调查 或阻碍完成。

4.总是对你的线程进行命名,线程名字能够在线程调试窗体里跟踪,所以做一个调试线程会使程式变得更有效。

Thread currentThread = Thread.CurrentThread; string threadName = \"Main UI Thread\"; currentThread.Name = threadName;

5.不要在线程中调用 Suspend() 和 Resume() 。

Suspend()挂起线程,或者如果线程已挂起,则不起作用。 Resume() 继续已挂起的线程。

6.不要调用Thread.Sleep()(将当前线程阻塞指定的毫秒数),除了下面的情况:

a)Thread.Sleep(0)对上下文的转换来说是一个可以接受的最优化的技术。 b)Thread.Sleep()在接受测试或模拟代码 7.不要调用Thread.SpinWait()导致线程等待。

8.不要调用Thread.Abort()去终止一个线程,不是标记线程的结束,而是应用同步对

象去完成。

9.避免显示设置线程的优先级来控制执行,你可以基于任务来设置线程的的优先级,使用屏幕存储器的线程应该低于一般水平。 (ThreadPriority.BelowNormal)

10.不要读取threadstate属性的value值,使用Thread.IsActive来确认该线程是否失效。

11.应用程式结束时,不要通过配置线程类型来设定线程。 使用workdog或其他监测实体来终止线程。

12.不要使用线程的本地存储,除非线程的关联性是有保障的。 13.不要调用thread.MemoryBarrier()。

(按如下方式同步内存访问:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier 调用之后的内存访问,再执行 MemoryBarrier 调用之前的内存访问的方式。)

14.在没有检查你是不是加入了自己的线程,不要调用Thread.Join()

(阻塞调用线程,直到某个线程终止时为止。)

15.始终使用lock()的声明,而不是用明显的monitor manipulation。

16.总是将lock()声明放在他所保护的对象里面。

public class MyClass {

public void DoSomething() {

lock(this) {...} } }

17.能够使用同步方法来代替您自己写lock()声明。 18.避免分散锁定。

19.避免用监控器去等待或刺激对象。应该用手工的或自动重起事件。

20.不要使用不稳定变量。锁定对象或域,而不是去确保决定性和线程安全访问。不要使用thread.volatileread(), thread.volatilewrite()或不稳定修改器。

21.在线程池里避免增加大量的线程。

22.永远不要重叠声明lock,因为这样不提供自动锁定。要使用waithandle.waitall()。

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序列化

{“序列化”可被定义为将对象的状态存储到存储媒介中的过程。在此过程中,对象的公共字段和私有字段以及类的名称(包括包含该类的程序集)都被转换为字节流,然后写入数据流。在以后“反序列化”该对象时,创建原始对象的精确复本。

一、为什么要选择序列化

一个原因是将对象的状态保持在存储媒体中,以便可以在以后重新创建精确的副本; 另一个原因是通过值将对象从一个应用程序域发送到另一个应用程序域中。

例如,序列化可用于在 ASP.NET 中保存会话状态并将对象复制到 Windows 窗体的剪贴板中。远程处理还可以使用序列化通过值将对象从一个应用程序域传递到另一个应用程序域中。

二、如何实现对象的序列化及反序列化

要实现对象的序列化,首先要保证该对象可以序列化。而且,序列化只是将对象的属性进行有效的保存,对于对象的一些方法则无法实现序列化的。

1、XML序列化

使用 XmLSerializer 类,可将下列项序列化。 公共类的公共读/写属性和字段

实现 ICollection 或 IEnumerable 的类。(注意只有集合会被序列化,而公共属性却不会。) XmlElement 对象。 XmlNode 对象。 DataSet 对象. 2、二进制序列化

与XML序列化不同的是,二进制序列化可以将类的实例中所有字段(包括私有和公有)都进行序列化操作。这就更方便、更准确的还原了对象的副本。}

1.最好使用二进制格式来序列化。 2.把序列化事件的处理方法标记为私有的。 3.使用IGenericFormatter接口。

4.把非密封的类标记为序列化的。使用sealed 修饰符时,此修饰符会阻止其他类从该类继承。

5.指示在完成整个对象图形的反序列化时通知类。在整个对象图形已经反序列化时运行。 6.当在一个非密封类里使用IDeserializationCallback 的时候,确保子类能调用基类中的OnDeserialization().

7.总是标记未序列化的成员变量为[non-serializable] 8.总是标记序列化类中的委托为[nonserialized]

[Serializable] public class MyClass {

[field:NonSerialized]

public event EventHandler MyEvent; }

4.5远程操作Remoting

什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式。从微软的

产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合

到.Net平台下。Microsoft® .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这也正是我们使用Remoting的原因。为什么呢?在Windows操作系统中,是将应用程序分离为单独的进程。这个进程形成了应用程序代码和数据周围的一道边界。如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一进程。这是一种操作系统对应用程序的保护机制。然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。

在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。Remoting的通道主要有两种:Tcp和Http。在.Net中,System.Runtime.Remoting.Channel中定义了IChannel接口。IChannel接口包括了TcpChannel通道类型和Http通道类型。它们分别对应Remoting通道的这两种类型。

1.宁可使用管理配置(配置文档)而不使用程式自动配置。

2.总是在单独调用对象里完成idisposable。(用于释放对象资源的接口) 3.远程操作时总是选用tcp信道和二进制格式 ,除非配置了防火墙。 4.总是为一个对象提供一个null租约。

public class MySingleton : MarshalByRefObject {

public override object InitializeLifetimeService() {

return null; } }

5.总是为客户端激活的对象提供sponsor。这个sponsor应该返回初始租约时刻。 发起人(Sponsor)

发起人是针对客户端而言的。远程对象就是发起人要租用的对象,发起人可以与服务器

端签订租约,约定租用时间。一旦到期后,发起人还可以续租,就像现实生活中租方的契约,房东、租房者之间的关系一样。

6.在客户端应用程式停止时总是不要注册sponsor。 7.总是将远程对象放在类库里。 8.避免使用soapsuds。

XML 架构自动转换为运行库程序集。该工具在生成程序集时始终会生成源代码。 9.避免宿主iis.

宿主iis优点是客户第一次请求的时候,宿主进程自动被启动。就是说“消息驱动服务”。并且可以使用IIS

管理宿主进程的生命周期(life cycle)。

缺点是:只能使用HTTP协议绑定(Http Binding)。

10.避免使用单一方向的信道。

11.总是在main()方法里载入远程配置文档,即使该文档为空。并且该应用程式没有使用远程操作。

static void Main() {

RemotingConfiguration.Configure(\"MyApp.exe.config\"); /* Rest of Main() */ }

12.避免对远程对象激活时使用activator.getobject() and activator.createinsta

nce()。而是使用new。

13.总是在客户端注册port(),目的是允许递归调用。

14.总是将客户端和服务器端的类型过滤配置为full,使其能够递归调用。

4.6 安全

1.总是使用强名称发布代码,该名称对于该应用程式而言是私有的,对于您是公有的。

public class PublicKeys {

public const string MyCompany = \"12345674800000940000000602000000240000\"+

\"52534131000400000100010007D1FA57C4AED9F0\"+ \"A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C83\"+ \"4C99921EB23BE79AD9D5DCC1DD9AD23613210290\"+ \"0B723CF980957FC4E177108FC607774F29E8320E\"+ \"92EA05ECE4E821C0A5EFE8F15C4C0C93C1AB99\"+ \"285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF\"+ \"0FC4963D261C8A12436518206DC093344D5AD293\";

}

[StrongNameIdentityPermission(SecurityAction.LinkDemand,

PublicKey = PublicKeys.MyCompany)] public class MyClass

{...}

2.对应用程式配置文档要实施加密和安全保护。

3.当引入一个互操作方法时,要断言不可控代码操作允许,并且声明相应的允许权限。

[DllImport(\"user32\

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

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

[UIPermission(SecurityAction.Demand,

Window = UIPermissionWindow.SafeTopLevelWindows)]

public static void Show(string text,string caption) {

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

4.不要通过suppressunmanagedcodesecurity属性来抑制不可控代码的访问。 5.不要使用tlbimp.exe这个不安全转换程式。将ccw包含于可控代码内,使您能够断言和授权。

6.在服务器端发布代码访问策略,授权给microsft, ecma和自身为全信任。 7.在客户端服务器,发布安全策略授权给客户端应用程式,使其有权回调服务器端程式并且能够潜在的显示用户界面。 客户端的应用程式应该予以强名称坚定。

8.在权限集水平总是拒绝权限,因为在附近不能被请求去执行任务。

[assembly:UIPermission(SecurityAction.RequestRefuse,

Window=UIPermissionWindow.AllWindows)]

9.总是在每一个main()方法里对windows应用principal策略

public class MyClass {

static void Main() {

AppDomain currentDomain = Thread.GetDomain();

currentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); }

//other methods }

10.在没有需要一个不同的权限的情况下,不可断言一个权限。

4.7 System.Transactions

使用 System.Transactions 命名空间包含的类可以编写自己的事务应用程序和资源管理器。具体地说,可以创建和参与(与一个或多个参与者)本地或分布式事务。

1.总是处理TransactionScope对象。使代码块成为事务性代码 2.在一个事务的范围之内,在调用complete()之后不要运行任何代码。 3.指示范围中的所有操作都已成功完成。

4.当设置环境中的事务的时候,总是保存旧的环境中的事务并备份它。 5.在发布版本的时候,不要设置事务超时为0(永不超时)。

6.当克隆一个事务的时候,总是使用DependentCloneOption.BlockCommitUntilComplete.

依赖事务阻塞事务的提交过程,直至父事务超时或 Complete 被调用。在此情况下,可以在该事务上完成附加工作,并且可以创建新的登记。

7.为每一个工作线程创建一个新的克隆。不要把相同的克隆作用于多个线程。 8.不要通过事务去克隆TransactionScope的构造器。 9.始终捕捉和抛出TransactionScopeOption.Suppress。

4.8企业服务

1.在事务方法里不要捕获异常。要用autocomplete属性。

2.不要调用setcomplete(), setabort(),连同相关方法。要用autocomplete属性。

[Transaction]

public class MyComponent : ServicedComponent {

[AutoComplete]

public void MyMethod(long objectIdentifier) {...} }

3.总是覆写canbepooled方法并且返回true(除非您有更好的原因不用返回值)。

public class MyComponent : ServicedComponent {

protected override bool CanBePooled() {

return true; } }

4.总是在对象池里显示地调用dispose(),除非该组件已被配置为使用JITA。

5.当组件使用JITA时不可调用dispose()。 6.总是为应用程式和组件配置权限水平。 7.将任何应用程式的检证水平配置为私有。

[assembly: ApplicationActivation(ActivationOption.Server)]

[assembly: ApplicationAccessControl(

true, //Authorization AccessChecksLevel=AccessChecksLevelOp

tion.ApplicationComponent, Authentication=AuthenticationOption.Privacy, ImpersonationLevel=ImpersonationLevelOption.Identify)]

8.将客户端程式集的角色水平配置为identity。

9.总是将可服务组件的componentaccesscontrol属性配置为true。

[ComponentAccessControl]

public class MyComponent : ServicedComponent {...}

10.总是将每一个用户角色配置为marshaler。

[assembly: SecurityRole(\"Marshaler\= true)]

11.应用securemethod属性于任何的需要检证的类。

[SecureMethod]

public class MyComponent : ServicedComponent

{...}

因篇幅问题不能全部显示,请点此查看更多更全内容