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了。
*成员访问性
![](http://images0.cnblogs.com/blog/199662/201309/11113232-5c7244189e4b425fa1d5745caac56b0e.png)
* c#要求原始成员和重写成员具有相同的可访问性
* string 和StringBuilder
摘自http://blog.csdn.net/angelazy/article/details/8501776
C#(静态String类)
C#中提供了比较全面的字符串处理方法,很多函数都进行了封装为我们的编程工作提供了很大的便利。System.String是最常用的字符串操作类,可以帮助开发者完成绝大部分的字符串操作功能,使用方便。
1. 比较字符串
比较字符串是指按照字典排序规则,判定两个字符的相对大小。按照字典规则,在一本英文字典中,出现在前面的单词小于出现在后面的单词。在String类中,常用的比较字符串的方法包括Compare、CompareTo、CompareOrdinal以及Equals,下面进行详细介绍。
Compare方法是String类的静态方法,用于全面比较两个字符串对象,包括6种重载方法。CompareTo方法将当前字符串对象与另一个对象做比较,其作用与Compare类似,返回值也相同。CompareTo与Compare相比,区别在于:CompareTo不是静态方法,可以通过一个String对象调用;CompareTo没有重载形式,只能按照大小写敏感方式比较两个整串。
Equals方法用于方便地判定两个字符串是否相同,有两种重载形式:
public boolEquals(string)
public static boolEquals(string,string)
如果两个字符串相等,Equals()返回值为True;否则,返回False。
String支持两个比较运算符“==”、“!=”,分别用于判定两个字符是否相等和不等,并区分大小写。相对于上面介绍的方法,这两个运算符使用起来更加直观和方便。下例中,使用“==”、“!=”对“Hello”和“World”进行比较。
2. 定位字符串和子串
定位子串是指在一个字符串寻找其中包含的子串或者某个字符,在String类中,常用的定位子串和字符的方法包括StartWith/EndsWith、IndexOf/LastIndexOf以及IndexOfAny /LastIndexOf下面进行详细介绍。
StartWith/EndsWithStartWith方法
可以判定一个字符串对象是否以另一个子字符串开头,如果是返回True;否则返回False。其定义为:
Public bool StartsWith(string value) //其中,参数value即待判定的子字符串。
IndexOf/LastIndexOf
IndexOf方法用于搜索一个字符串,某个特定的字符或子串第一次出现的位置,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包含这个字符或子串,则返回-1。共有如下6种重载形式。
定位字符:
- intIndexOf(charvalue)
- intIndexOf(charvalue,intstartIndex)
- intIndexOf(charvalue,intstartIndex,intcount)
定位子串:
- intIndexOf(stringvalue)
- intIndexOf(stringvalue,intstartIndex)
- intIndexOf(stringvalue,intstartIndex,intcount)
在上述重载形式中,其参数含义如下:
Value:待定位的字符或者子串。
startIndex:在总串中开始搜索的起始位置。
Count:在总串中从起始位置开始搜索的字符数。
IndexOfAny/LastIndexOfAnyIndexOfAny方法
其功能同IndexOf类似,区别在于,可以搜索在一个字符串中,出现在一个字符数组中的任意字符第一次出现的位置。同样,该方法区分大小写,并从字符串的首字符开始以0计数。如果字符串中不包括这个字符或子串,则返回-1。IndexOfAny有3种重载形式:
- intIndexOfAny(char[] anyOf)
- intIndexOf(char[] anyOf,intstartIndex)
- 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方法
若想把一个字符串首尾处的一些特殊字符剪切掉,如去掉一个字符串首尾的空格等,可以使用String的Trim()方法。其形式如下:
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类似,TrimStart和TrimEnd分别剪切掉一个字符串开头和结尾处的特殊字符。
8. 复制字符串
String类包括了复制字符串方法Copy和CopyTo,可以完成对一个字符串及其一部分的复制操作。
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);
其中,参数oldChar和oldValue为待替换的字符和子串,而newChar和newValue为替换后的新字符和新子串。下例把“Hello”通过替换变为“Hero”。
//Replace
newStr=strA.Replace("ll","r");
Console.WriteLine(newStr);
10. 更改大小写
String提供了方便转换字符串中所有字符大小写的方法ToUpper和ToLower。这两个方法没有输入参数,使用也非常简单。下例首先把“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字符串的结尾处,可以使用Append和AppendFormat来实现这个功能。
1. Append方法
Append方法实现简单的追加功能,常用形式为:
public StringBuilder Append(object value);
其中,参数value既可以是字符串类型,也可以是其他的数据类型,如bool、byte、int等。下例中,把一个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);
其中,参数oldChar和oldValue为待替换的字符和子串,而newChar和newValue为替换后的新字符和新子串。
下例把“Hello”通过替换为“Hero”。
//Replace
StringBuilder sb8=new StringBuilder("Hello");
sb8=sb8.Replace("ll","r");
Console.WriteLine(sb8); //Hero
7. 与String比较
通过上面的介绍,可以看出StringBuilder与String在许多操作上(如Insert、Remove、Replace)上是非常相似的。
在操作性能和内存效率方面,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则用在需要被调用的方法修改调用者的引用的时候。