.NET开发总结 2010年2月

总结一些常见的.NET开发技巧。虽然网上已经有很多例子,如果按照自己的思路来写,温固而知新。
自己再重敲一遍的印象会更加深刻。

1 扩展方法
在不改变一个类型的源代码(或者说无法得到类型的源代码)的情况下,如何扩展一个类型的功能
a) 继承。从该类派生出子类,在子类中作扩展。前提条件是该类不是密封的,也即不能被sealed修饰
继承的目的是代码复用。
b) 组合  把该类添加到另一个类中作为一个变量,根据需要扩展该类的相应方法
c) 扩展方法,举例如下
public static class StringHelper
{
  public static bool IsCapitalized (this string s)
  {
    if (string.IsNullOrEmpty(s)) return false;
    return char.IsUpper(s[0]);
  }
}
调用示例:Console.WriteLine("Perth".IsCapitalized(  ));
扩展方法是编译器提供的一个技巧,它会在编译时,把它编译为类的一个静态方法,实际运行时会是这样
Console.WriteLine(StringHelper.IsCapitalized("Perth"));
扩展方法要求是静态类的静态方法,this关键字修饰方法的第一个参数,第一个参数的参数类型是被扩展的类型是,如果对扩展方法的调用均会转化为类的静态方法调用

arg0.Method(arg1, arg2, ...);       // 扩展方法调用
转换为下面的静态方法调用

StaticClass.Method(arg0, arg1, arg2, ...); // 静态方法调用

如果一个类型有很多个扩展方法,会形成一个扩展方法的链(Chaining),如代码所示
public static class StringHelper
{
  public static string Pluralize (this string s) {...}
  public static string Capitalize (this string s) {...}
}
下面的两种调用方式产生的效果一样
string x = "sausage".Pluralize().Capitalize(  ); //扩展方法
string y = StringHelper.Capitalize (StringHelper.Pluralize("sausage")));//静态方法

对于使用扩展方法重载类型的实例方法,如下代码
class Test
{
  public void Foo (object x) { }   
}
static class Extensions
{
  public static void Foo (this Test t, int x) { }
}
实例方法总是优先被调用。如
Test t=new Test();

t.Foo(10); //这里会调用Test.Foo()方法,而不是Extensions.Foo()方法
如果需要调用扩展方法,语法应该是Extensions.Foo(10);

2 可以修饰方法的参数的关键字
this 用于扩展方法
ref 把值类型以传引用的方式传进方法体中,传入前方法体前要初始化
out把值类型以传引用的方式传进方法体中,方法体返回前要初始化
params 定义不确定的方法参数
public static void ParamsHelper(param object [] parts)
{  foreach(object obj in parts)
            Console.WriteLine(obj);
}

3  预处理指令(Preprocessor Directives)
先看例子,如下
#define DEBUG
class MyClass
{
  int x;
  void Foo(  )
  {
    # if DEBUG
    Console.WriteLine("Testing: x = {0}", x);
    # endif
  }
}
如果我们删除DEBUG符号的定义(文件开头的#define DEBUG), Console.WriteLine("Testing: x = {0}", x); 语句将会被编译器忽略,不会被编译到程序集中。
也可以通过编译器开关(/define)指定的符号值
这个特性可以通过同一套源码,制作出不同版本发行程序。比如一个ERP程序,有专业版(Professionals),企业版(Enterprise),集团版(Group);或者同一套源码,不同的客户对相对的逻辑有不同的实现方法,如WIP的计算方法,或是成本的计算方法各不相同。有一种办法是把一份源代码拷贝三份,分别实现,这现带来的很多问题。
借助这个方法,可以给编译器传递不同的编译参数(/define),编译器根据不同的参数编译出不同的版本。

4 运算符重载(Operator Overloading)
直接上例子代码
public struct Note
{
  int value;
  public Note (int semitonesFromA) { value = semitonesFromA; }
  public static Note operator + (Note x, int semitones
  {
    return new Note (x.value + semitones);
  }
}
现在,可以使用下面的方法
Note B = new Note(2);
Note CSharp = B + 2; //注意这里,B是一个引用类型,而2是值类型
也可以用CSharp += 2;
之前我有写过模具行业的知识,里面有一个公式
Insert=Cavity +Core +Sub Insert
Cavity 和Core 可以理解成一个部件(part),是组成产品的一部分。如果我创建三个类型,可以通过这里的技巧,直接把它们相加得到另一个类型
如下面的代码
public class Cavity {  }
public class Core{  }
public class Insert { }
可以在Insert 类型中,组合Cavity 和Core,如下面的伪码
Insert insert ; Cavity cav; Core core;
insert =cav+ core
但是不能完全模仿这个例子,因为例子中的参数是int,而我写出的公式是cav+ core,两个类型的实例相加,需要把重载运算符中的参数换成另一个类型。

5 显式或隐式类型转换
看例子
public static implicit operator double(Note x)
{
return 440 * Math.Pow (2,(double) x.value / 12 );
}
public static explicit operator Note(double x)
{
return new Note ((int) (0.5 + 12 * (Math.Log(x/440) / Math.Log(2)) ));
}
调用方法
Note n =(Note)554.37; //显式转换,把值类型转换为引用类型
double x = n;              // 隐式转换,把引用类型转换为值类型

6 序列化(Serialization)
有四种序列化方式:Xml,Binary,SOAP,和DataContract
具体的代码就不写了,只讲我使用过的应用。
二进制序列化常用来存储一些临时的中间文件。比如在一个Win Forms应用程序中,每次用户要求记住用户名,在登陆的时候不要重复输入。Web应用中可以用Cookie解决,桌面应用中可以用这个方法。在验证用户登陆成功时,把用户名序列化成一个文件,存储在相应的目录中。每次启动系统登陆页面时,查找是否存在该文件,如果存在就把它反序列化,把值放到输入用户名的文本框中。
Xml应用于多个字段值的存储于一个数据库列中。在SQL Server中定义一个字符串字段
CREATE TABLE Report(summary varchar(200) )
这个字段可以存多个字段的值。如果界面中的中间计算结果值有多个,但是又不愿意为他们各自开一个列来存储,可以尝试用这种方法。
SQL Server 2005中直接支持xml类型,可以方便的查询和检索xml片段值的不同元素的值。
DataContract是WCF中提供的一种方式,如果要用WCF传递对象,需要给实体类加上DataContract特性,同时需要封送的成员还要加上DataMember特性。
SOAP在xml web service中应用的广泛。

7 如何使用嵌入的资源文件
比如,将一个位图文件嵌入到程序集中(点击文件属性,Build Action设置为Embedded Resource。使用下面的样例代码访问嵌入到程序集中的资源
string bmpName = "WindowsApplication6.subfolders.sync.bmp";
System.IO.Stream strm = null;
try
{
     strm = this.GetType().Assembly.GetManifestResourceStream(bmpName);
     pictureBox1.Image = new Bitmap(strm);
     // Do the same for Icons
     // Icon icon1 = new Icon(strm);
}
catch(Exception e)
{
     MessageBox.Show(e.Message);
}
finally
{
     if(strm != null)
          strm.Close();
}

8  如何获得不区分大小写的子字符串的索引位置
1)通过将两个字符串转换成小写之后使用字符串的IndexOf方法:
string strParent = "The Codeproject site is very informative.";
string strChild = "codeproject";
int i = strParent.IndexOf(strChild);
int j = strParent.ToLower().IndexOf(strChild.ToLower());
2) 使用System.Globalization命名空间下面的CompareInfo类的IndexOf方法:
using System.Globalization;
string strParent = "The Codeproject site is very informative.";
string strChild = "codeproject";
  CompareInfo Compare = CultureInfo.InvariantCulture.CompareInfo;
int i = Compare.IndexOf(strParent,strChild,CompareOptions.IgnoreCase);

9  拷贝构造函数
构造函数是用来初始化我们要创建实例的特殊的方法.
如何通过赋值的同时创建一个全新的变量而不只是对实例引用的赋值,应当使用拷贝构造函数
public Part(Part part) 

this.name = part.name;
}

class Part
  {
      private string name;
      public Part(string name)
       {
          this.name = name;
      }
      public Part(Part  part)
       {
          this.name = part.name;
      }
     public string Name
      {
        get
         {
               return name;
        }
        set
         {
             name = value;
        }
     }
}
class Final
  {
     static void Main()
        {
         Part a= new Part("A");
         Part  b= new Part(a); 
         a.Name = "B";
         System.Console.WriteLine("The part name is {0}", b.Name);
       }
}

10  VB与C#代码转换工具
在下面的网页中有在线转换工具
http://csharpconverter.claritycon.com/Default.aspx 或者http://www.kamalpatel.net/ConvertCSharp2VB.aspx
如果没有办法连接到因特网,可以尝试SharpDevelop这个软件。

posted @ 2010-02-21 08:33  信息化建设  阅读(922)  评论(0编辑  收藏  举报