0910

*CLR支持两种程序集:弱命名程序集(weakly named assembly)和强命名程序集(strongly named assembly)。

摘自:http://www.cnblogs.com/pursue/archive/2009/08/15/1546968.html

强命名程序集的缘由:

    目前Windows中出现的DLL Hell问题(两个不同的公司可能开发处具有相同名称的程序集,如果将相同名称的程序 集放置到同一个目录下,则会出现程序集覆盖现象,最后安装的程序集会覆盖前面的程序集,从而可能导致应用序不能正常运行)。由此看来,仅靠名称来区分程序集是不足够的。CLR采取了强命名程序集的方式来唯一的表示程序集。强命名程序集包含四个标识:名称,版本号,语言文化标识和一个共有/私有密钥对。

    两种程序集/两种部署方式:.Net支持两种程序集:弱命名程序集和强命名程序集(注:.Net框架中没有弱命名程序集,只是为了和强命名程序集相对应而已)。

    弱命名程序集和强命名程序集在结构上是相同的。他们都采用PE文件格式,包含PE表头,CLR表头,元数据和清单表。

     区别在于:强命名程序集拥有一个发布者的公钥/私钥签名对,他们用于唯一的标识程序集的发布者。通过公钥/私钥对,我们可以对程序集进行唯一的标识,安全策略和版本策略。

    强名称主要用处:就是防止dll被随意引用,另外控制版本,标识唯一性。

*Microsoft标准的公钥/私钥加密技术包括: 全局唯一标识符 Globally Unique Identifier GUID;统一资源定位符 URL Uniform Resource Locator;统一资源名称(Uniform Resource Name)

摘自:http://blog.csdn.net/flyerwing/article/details/4707083

创建一个强命名程序集首先需要获得一个用强命名实用工具(Strong Name Utility,即SN.exe,.NET SDK自带)产生的密钥。密钥文件可以以.Keys结尾也可以以.snk结尾????
  下面简要介绍一下SN.exe的一些用法。 要产生一个公钥/私钥对:
    a)SN –k MyCompany.Keys
   该命名告诉SN.exe创建一个名为MyCompany.keys的文件。MyCompany.keys文件将包含以对以二
进制格式存储的公有密钥和私有密钥。

    b)查看公有密钥:
   首先生成一个只包含公有密钥的文件:SN –p MyCompany.keys MyCompany.PublicKey
   然后用-tp参数查看:SN –tp MyCompany.PublicKeys
    Public key is 0024000004800000940000000602000000240000525341310004000001000100bb7214723ffc13901343df4b9c464ebf7ef4312b0ae4d31db04a99673e8

163768cc0a2a7062e731dbeb83b869f0509bf8009e90db5c8728e840e782d2cf928dae35c2578ec55f0d11665a30b37f8636c08789976d8ee9fe9a5
    c4a0435f0821738e51d6bdd6e6711a5acb620018658cce93df37d7e85f9a0104a5845053995ce8
    Public key token is 2dc940d5439468c2

如图

创建好的公钥/私钥 所在路径即为:D:\Program Files\Microsoft Visual Studio 10.0\VC 下
   创建好了公钥/私钥对,创建强命名程序集就很容易了。只需要它加入到程序集中即可:在解决方案中右键项目--选择属性--签名--勾选为程序集签名--浏览签名文件MyCompany.Keys--保存 即可

 

关于System.Object

*所有类型都从System.Object派生;

*称为类的类型都是引用类型;引用类型在堆上分配;引用类型总是处于已装箱状态;

*称为结构或是枚举的都是值类型,所有值类型从System.ValueType派生, 结构都是从抽象类型System.ValueType直接派生的,而枚举是从Systme.Enum中直接派生,System.Enum是从System.ValueType派生;值类型在栈上分配;值类型对象有两种表示形式:未装箱(unboxed)和已装箱(boxed)

 *不要使用GetHashCode方法对哈希码进行持久化,不同版本的CLR可能采用不同的方式获得哈希码

 * dymanic关键字;

*类型可见性指定为指定为public或internal.public 类型不仅对它的定义程序集中的所有代码可见,还对其他程序集中的代码可见。internal类型仅对定义程序集中的所有代码可见,对其他程序集中的代码不可见。不显式指定类型可见性的话,默认为internal

友元程序集 参考http://www.cnblogs.com/oec2003/archive/2010/11/15/1877390.html

C#中的访问修饰符Internal可以说是介于Public和Private之间,可以使类型在同程序集中可以被互相访问。但有时会有这样的需 求,我们希望一个程序集中的类型可以被外部的某些程序集可以访问,这时当然不能设置成Public,否则可以被所有的外部程序集访问。要达到上述要求我们 可以使用友元程序集。

下面用一个简单的例子来介绍下友元程序集。

1 在一个解决方案中创建两个类库项目TestA和TestB,分别在两个类库项目中创建类A和类B。

2 在项目TestA中添加对项目TestB的引用。

3 将项目TestB中的类B访问级别设置为Internal。

namespace TestB
{
    internal class B
    {
        
    }
}

4 现在在TestA项目的类A中是肯定不能访问到类B的,如果想让类A可以访问类B,必须将项目TestA的程序集添加为项目TestB程序集的友元程序集。添加友元程序集我们要使用InternalIsVisibleTo特性,使用该特性需要添加命名空间

using System.Runtime.CompilerServices。

5 在B类中使用InternalIsVisibleTo特性将程序集TestA添加为友元程序集。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("TestA")]
namespace TestB
{
    internal class B
    {
        
    }
}
7 现在在项目TestA的类A中就可以访问TestB项目的类B了。

*成员访问性

* c#要求原始成员和重写成员具有相同的可访问性

*sealed关键字:对某个类使用 sealed关键字作为前缀,这样可以防止其他类继承自该类;密封方法,从而其他派生类不可以重写在当前类中提供的实现

 * string 和StringBuilder

摘自http://blog.csdn.net/angelazy/article/details/8501776

C#(静态String类)

C#中提供了比较全面的字符串处理方法,很多函数都进行了封装为我们的编程工作提供了很大的便利。System.String是最常用的字符串操作类,可以帮助开发者完成绝大部分的字符串操作功能,使用方便。

1. 比较字符串

比较字符串是指按照字典排序规则,判定两个字符的相对大小。按照字典规则,在一本英文字典中,出现在前面的单词小于出现在后面的单词。在String类中,常用的比较字符串的方法包括CompareCompareToCompareOrdinal以及Equals,下面进行详细介绍。

Compare方法String类的静态方法,用于全面比较两个字符串对象,包括6种重载方法。CompareTo方法将当前字符串对象与另一个对象做比较,其作用与Compare类似,返回值也相同。CompareToCompare相比,区别在于:CompareTo不是静态方法,可以通过一个String对象调用;CompareTo没有重载形式,只能按照大小写敏感方式比较两个整串。

Equals方法用于方便地判定两个字符串是否相同,有两种重载形式:

public boolEquals(string)

public static boolEquals(string,string)

如果两个字符串相等,Equals()返回值为True;否则,返回False

String支持两个比较运算符“==”、“!=,分别用于判定两个字符是否相等和不等,并区分大小写。相对于上面介绍的方法,这两个运算符使用起来更加直观和方便。下例中,使用“==”、“!=”对“Hello”和“World”进行比较。

2. 定位字符串和子串

定位子串是指在一个字符串寻找其中包含的子串或者某个字符,在String类中,常用的定位子串和字符的方法包括StartWith/EndsWithIndexOf/LastIndexOf以及IndexOfAny /LastIndexOf下面进行详细介绍。

StartWith/EndsWithStartWith方法

可以判定一个字符串对象是否以另一个子字符串开头,如果是返回True;否则返回False。其定义为:

Public bool StartsWith(string value) //其中,参数value即待判定的子字符串。

IndexOf/LastIndexOf

IndexOf方法用于搜索一个字符串,某个特定的字符或子串第一次出现的位置,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包含这个字符或子串,则返回-1。共有如下6种重载形式。

定位字符:

  1. intIndexOf(charvalue)
  2. intIndexOf(charvalue,intstartIndex)
  3. intIndexOf(charvalue,intstartIndex,intcount)

定位子串:

  1. intIndexOf(stringvalue)
  2. intIndexOf(stringvalue,intstartIndex)
  3. intIndexOf(stringvalue,intstartIndex,intcount)

在上述重载形式中,其参数含义如下:

Value:待定位的字符或者子串。

startIndex:在总串中开始搜索的起始位置。

Count:在总串中从起始位置开始搜索的字符数。

IndexOfAny/LastIndexOfAnyIndexOfAny方法

其功能同IndexOf类似,区别在于,可以搜索在一个字符串中,出现在一个字符数组中的任意字符第一次出现的位置。同样,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包括这个字符或子串,则返回-1IndexOfAny3种重载形式:

  1. intIndexOfAny(char[] anyOf)
  2. intIndexOf(char[] anyOf,intstartIndex)
  3. intIndexOf(char[] anyOf,intstartIndex,intcount)

在上述重载形式中,参数含义如下:

anyOf:待定位的字符数组,方法将返回这个数组中任意一个字符第一次出现的位置。

startIndex:在总串中开始搜索的起始位置。

Count:在总串中从起始位置开始搜索的字符数。

3. 格式化字符串

Format方法用于创建格式化的字符串以及连接多个字符串对象。Foramt方法也有多个重载形式,最常用的为:

public static string Format(string format,params object[] args);

其中,参数format用于指定返回字符串的格式,而args为一系列变量参数。可以通过下面的实例来掌握其使用方法。

newStr="";

newStr=String.Format("{0},{1}!",strA,strB);

Console.WriteLine(newStr);//Hello,World!

format参数中包含一些用大括号括起来的数字,如{0}{1},这些数字分别一一对应于args参数数组中的变量。在生成结果字符串时,将使用这些变量代替{i}。需要说明的是,这些变量并不要求必须为String类型。在特定的应用中,Format方法非常方便。例如,想要输出一定格式的时间字符串,便可以使用Format方法,如下面代码所示。

newStr=String.Format("CurrentTime={0:yyyy-MM-dd}",System.DateTime.Now);

Console.WriteLine(newStr);//形如:2006-05-19

其中,格式字符串“yyyy-MM-dd”指定返回时间的格式形如“2006-05-19”,其定义参考System.Globalization.DateTimeFormatInfo类。

4. 连接字符串

Concat方法

Concat方法用于连接两个或多个字符串。Concat方法也有多个重载形式,最常用的为:public static string Concat(paramsstring[] values);其中,参数values用于指定所要连接的多个字符串,可以通过下面的实例来掌握其使用方法。

//ConcatnewStr="";

newStr=String.Concat(strA," ",strB);

Console.WriteLine(newStr);//Hello World"

Join方法

Join方法利用一个字符数组和一个分隔符串构造新的字符串。常用于把多个字符串连接在一起,并用一个特殊的符号来分隔开。Join方法的常用形式为:public static string Join(stringseparator,string[] values);其中,参数value为指定的分隔符,而values用于指定所要连接的多个字符串数组,下例用“^^”分隔符把“Hello”和“World”连起来。

//Join

newStr="";

String[] strArr={strA,strB};

newStr=String.Join("^^",strArr);

Console.WriteLine(newStr);//"Hello^^World"

连接运算符“+

String支持连接运算符“+”,可以方便地连接多个字符串,例如,下例把“Hello”和“World”连接起来。

newStr="";

newStr=strA+strB;

Console.WriteLine(newStr);//"HelloWorld"

5. 分隔字符串

使用前面介绍的Join方法,可以利用一个分隔符把多个字符串连接起来。反过来,使用Split方法可以把一个整串,执照某个分隔符,分裂成一系列小的字符串。例如,把整串,按照某个分隔符,分裂成一系列小的字符串。例如,把整串“Hello^^World”按照字符“^”进行分裂,可以得到3个小的字符串,即“Hello”、“”(空串)和“World”。

Split有多个重载形式,最常用的形式为:

public string[] Split(paramschar[] separator);

其中,参数separator数组包含分隔符。下例把“Hello^^World”进行分裂

//Split

newStr="Hello^^World";

char[] separator={'^'};

String[] splitStrings=new String[100];

splitStrings=newStr.Split(separator);

inti=0;

while(i<splitStrings.Length)

{

Console.WriteLine("item{0}:{1}",i,splitStrings[i]);

i++;

}

输出结果如下:Item0:Hello Item1:  Item2:World

6. 插入和填充字符串

String类包含了在一个字符串中插入新元素的方法,可以用Insert方法在任意插入任意字符。Insert方法用于在一个字符串的指定位置插入另一个字符串,从而构造一个新的串。Insert方法也有多个重载形式,最常用的为:

public string Insert(intstartIndex,stringvalue);

其中,参数startIndex用于指定所要插入的位置,从0开始索引;value指定所要插入的字符串。下例中,在“Hello”的字符“H”后面插入“World”,构造一个串“HWorldello”。

//Insert

newStr="";

newStr=strA.Insert(1,strB);

Console.WriteLine(newStr);//"HWorldello"

7. 删除和剪切字符串

Remove方法

Remove方法从一个字符串的指定位置开始,删除指定数量的字符。最常用的形式为:

public string Remove(intstartIndex,intcount);

其中,参数startIndex用于指定开始删除的位置,从0开始索引;count指定删除的字符数量。下例中,把“Hello”中的“ell”删掉。

//RemovenewStr="";newStr=strA.Remove(1,3);

Console.WriteLine(newStr);//"Ho"

Trim/TrimStart/TrimEnd

Trim方法

若想把一个字符串首尾处的一些特殊字符剪切掉,如去掉一个字符串首尾的空格等,可以使用StringTrim()方法。其形式如下:

public string Trim();

public string Trim(paramschar[] trimChars);

其中,参数trimChars数组包含了指定要去掉的字符,如果缺省,则删除空格符号。下例中,实现了对“@Hello#$”的净化,去掉首尾的特殊符号。

//Trim

newStr="";

char[] trimChars={'@','#','$',' '};

String strC="@Hello# $";

newStr=strC.Trim(trimChars);

Console.WriteLine(newStr);//"Hello"

另外,同Trim类似,TrimStartTrimEnd分别剪切掉一个字符串开头和结尾处的特殊字符。

8. 复制字符串

String类包括了复制字符串方法CopyCopyTo,可以完成对一个字符串及其一部分的复制操作。

Copy方法

若想把一个字符串复制到另一个字符数组中,可以使用String的静态方法Copy来实现,其形式为:public string Copy(stringstr);其中,参数str为需要复制的源字符串,方法返回目标字符串。

CopyTo方法

CopyTo方法可以实现Copy同样的功能,但功能更为丰富,可以复制字符串的一部分到一个字符数组中。另外,CopyTo不是静态方法,其形式为:

public void CopyTo(intsourceIndex,char[] destination,intdestinationIndex,intcount);

其中,参数sourceIndex为需要复制的字符起始位置,destination为目标字符数组,destinationIndex指定目标数组中的开始存放位置,而count指定要复制的字符个数。

下例中,把strA字符串“Hello”中的“ell”复制到newCharArr中,并在newCharArr中从第2个元素开始存放。

char[] newCharArr=new char[100];

strA.CopyTo(2,newCharArr,0,3);

Console.WriteLine(newCharArr);//"Hel"

9. 替换字符串

要替换一个字符串中的某些特定字符或者某个子串,可以使用Replace方法来实现,其形式为:

 public string Replace(char oldChar, char newChar);

 public string Replace(string oldValue, string newValue);

 其中,参数oldCharoldValue为待替换的字符和子串,而newCharnewValue为替换后的新字符和新子串。下例把“Hello”通过替换变为“Hero”。

 //Replace

 newStr=strA.Replace("ll","r");

 Console.WriteLine(newStr);

10. 更改大小写

String提供了方便转换字符串中所有字符大小写的方法ToUpperToLower。这两个方法没有输入参数,使用也非常简单。下例首先把“Hello”转换为“HELLO”,然后再变为小写形式“hello”。

本节介绍了最常用的String类,并从比较、定位子串、格式化、连接、分裂、插入、删除、复制、大小写转换10个方面介绍了其方法。之所以称String对象为静态串,是因为一旦定义一个String对象,就是不可改变的。在使用其方法(如插入、删除操作)时,都要在内在中创建一个新的String对象,而不是在原对象的基础上进行修改,这就需要开辟新的内存空间。如果需要经常进行串修改操作,使用String类无疑是非常耗费资源的,这时需要使用StringBuilder类。

 

动态串StringBuilder

 

String类相比,System.Text.StringBuilder类可以实现动态字符串。此外,动态的含义是指在修改字符串时,系统不需要创建新的对象,不会重复开辟新的内存空间,而是直接在原StringBuilder对象的基础上进行修改。下面,将从各个应用的角度,详细讨论StringBuilder类。

 

1. 声明StringBuilder

 

StringBuilder类位于命名空间System.Text中,使用时,可以在文件头通过using语句引入该空间:

 

using System.Text;

 

声明StringBuilder对象需要使用new关键字,并可以对其进行初始化。如以下语句声明了一个StringBuilder对象myStringBuilder,并初始化为“Hello”:

 

StringBuildermyStringBuilder=new StringBuilder("Hello");

 

如果不使用using关键字在文件头引入System.Text命名空间,也可以通过空间限定来声明StringBuilder对象:

 

System.Text.StringBuildermyStringBuilder=new StringBuilder("Hello");

 

在声明时,也可以不给出初始值,然后通过其方法进行赋值。

 

2. 设置StringBuilder容量

 

StringBuilder对象为动态字符串,可以对其设置好的字符数量进行扩展。另外,还可以设置一个最大长度,这个最大长度称为该StringBuilder对象的容量(Capacity)。

 

StringBuilder设置容量的意义在于,当修改StringBuilder字符串时,当其实际字符长度(即字符串已有的字符数量)未达到其容量之前,StringBuilder不会重新分配空间;当达到容量时,StringBuilder会在原空间的基础之上,自动不进行设置,StringBuilder默认初始分配16个字符长度。有两种方式来设置一个StringBuilder对象的容量。

 

1.使用构造函数

 

 StringBuilder构造函数可以接受容量参数,例如,下面声明一个StringBuilder对象sb2,并设置其容量为100

 

//使用构造函数

 StringBuilder sb2=new StringBuilder("Hello",100);

 

2.使用Capacity/写属性

 Capacity属性指定StringBuilder对象的容量,例如下面语句首先一个StringBuilder对象sb3,然后利用Capacity属性设置其容量为100

 

//使用Capacity属性

 

 StringBuilder sb3=new StringBuilder("Hello");

 sb3.Capacity=100;

 

3. 追加操作

追加一个StringBuilder是指将新的字符串添加到当前StringBuilder字符串的结尾处,可以使用AppendAppendFormat来实现这个功能。

1. Append方法

 Append方法实现简单的追加功能,常用形式为:

 

 public StringBuilder Append(object value);

 

 其中,参数value既可以是字符串类型,也可以是其他的数据类型,如boolbyteint等。下例中,把一个StringBuilder字符串“Hello”追加为“Hello World!”。

 

 //Append

 StringBuilder sb4=new StringBuilder("Hello");

 sb4.Append(" World!");

 

2.AppendFormat方法

 AppendFormat方法可以实现对追加部分字符串的格式化,可以定义变量的格式,并将格式化后的字符串追加在StringBuilder后面。常用的形式为:

 StringBuilder AppendFormat(string format,params object[] args);

 其中,args数组指定所要追加的多个变量。format参数包含格式规范的字符串,其中包括一系列用大括号括起来的格式字符,如{0:u}。这里,0代表对应args参数数组中的第0个变量,而‘u’定义其格式。下例中,把一个StringBuilder字符串“Today is”追加“Today is *当前日期*\”。

 

 //AppendFormat

 StringBuilder sb5=new StringBuilder("Today is ");

 sb5.AppendFormat("{0:yyyy-MM-dd}",System.DateTime.Now);

 Console.WriteLine(sb5); //形如:"Today is 2008-10-20"

 

4. 插入操作

StringBuilder的插入操作是指将新的字符串插入到当前的StringBuilder字符串的指定位置,如“Hello”变为“Heeeello”。可以使用StringBuilder类的Insert方法来实现这个功能,常用形式为:

public StringBuilder Insert(int index, object value);

其中,参数index指定所要插入的位置,并从0开始索引,如index=1,则会在原字符串的第2个字符之前进行插入操作;同Append一样,参数value并不仅是只可取字符串类型。

5. 删除操作

StringBuilder的删除操作可以从当前StringBuilder字符串的指定位置,删除一定数量的字符,例如把“Heeeello”变为“Hello”。可以使用StringBuilder类的Remove方法来实现这个功能,常用形式为:

public StringBuilder Remove(int startIndex, int length);

其中,参数startIndex指定所要删除的起始位置,其含义同Insert中的index相同;length参数指定所要删除的字符数量。下例中,把一个StringBuilder字符串“Heeeello”通过删除操作修改为“Hello”。

 

 //Remove

 StringBuilder sb7=new StringBuilder("Heeello");

 sb7.Remove(2,3); //在”He”后面删除个字符

 Console.WriteLine(sb7); //"Hello!"

 

6. 替换操作

 StringBuilder使用Replace方法来实现替换操作,例如把“Hello”变为“Hero”,就需要使用替换操作,将“ll”替换为“r”。这同String类的Replace方法非常类似,其常用

形式包括:

 

public StringBuilder Replace(char oldChar, char newChar);

public StringBuilder Replace(string oldValue, string newValue);

 

 其中,参数oldCharoldValue为待替换的字符和子串,而newCharnewValue为替换后的新字符和新子串。

 下例把“Hello”通过替换为“Hero”。

 

 //Replace

 StringBuilder sb8=new StringBuilder("Hello");

 sb8=sb8.Replace("ll","r");

 Console.WriteLine(sb8); //Hero

 

7. 与String比较

通过上面的介绍,可以看出StringBuilderString在许多操作上(如InsertRemoveReplace)上是非常相似的。

 在操作性能和内存效率方面,StringBuilder要比String好得多,可以避免产生太多的临时字符串对象,特别是对于经常重复进行修改的情况更是如此。而另一方面,String类提供了更多的方法,可以使开发能够更快地实现应用。

在两者的选择上,如果应用对于系统性能、内存要求比较严格,以及经常处理大规模的字符串,推荐使用StringBuilder对象;否则,可以选择使用String

*ref 和out

对于值类型。

如果不使用ref /out则传递的只是这些值的COPY,使用了Ref和Out的效果就几乎和C中使用了指针变量一样。(传递的就是原值),它能够让你直接对原数进行操作,而不是对那个原数的Copy进行操作

 对于引用类型:

如果不使用ref /out,因为传递的是引用类型的地址值,则将传递引用类型的地址值的一个COPY(--针对地址值的角度还是值类型传递),实际上就是新开一个不同的内存变量来存储这个地址值的拷贝

Ref和Out关键字的区别:

 使用Ref型参数时,传入的参数必须先被初始化。而Out则不需要,对Out而言,就必须在方法中对其完成初始化

首先:两者都是按地址传递的,使用后都将改变原来的数值。很多人在论坛上解释说out是按数值传递,是错误的。简单的测试后可以知道out使用也能改变数值的,所以肯定是按照地址传递的。
其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所以你必须初始化一次。这个就是两个的区别,或者说就像有的网友说的,ref是有进有出,out是只出不进。经典!!!

Out更适合用在需要Return多个返回值的地方,而Ref则用在需要被调用的方法修改调用者的引用的时候。

 

 

 

 

posted @ 2013-09-10 15:53  nygfcn  阅读(258)  评论(0编辑  收藏  举报