.NET 基础知识
垃圾回收
最基本的5个设计原则
单一职责原则(SRP:Single Responsibility Principle):一个类,应该仅有一个引起它变化的原因,不要将变化原因不同的职责封装在一起,而应该隔离。
开放封闭原则(OCP,Open Closed Principle):软件实体应当对修改关闭,对扩展开放。
依赖倒置原则(DIP,Dependency Inversion Principle):依赖抽象,而不要依赖于具体,因为抽象相对稳定。
接口隔离原则(ISP,Interface Segregation Principle): 尽量应用专门的接口,而不是单一的总接口,接口应该面向用户,将依赖建立在最小的接口上。
Liskov替换原则(LSP,Liskov Substitution Pinciple): 子类必须能够替换其基类。
合成/聚合复用原则(CARP,Composite/Aggregate Reuse Principle)在新对象中聚合已有对象,使之成为新对象的成员,从而通过操作这些对象达到复用的目的。合成方式较继承方式耦合更松散,所以应该少继承。
·带params关键字的参数必须是最后一个参数;
·带params关键字的参数类型必须是一维数组(传递一个或者多个参数);
类
类中的成员,如果不加访问修饰符,则默认为private
类如果不加访问修饰符,则默认为internal
继承:
---好处
1.代码重用
2.多态(里氏替换原则LSP)
---特征
1.当写好一个类以后,默认会存在一个没有参数的构造函数(即便我们不写构造函数,也会存在这么一个无参的构造函数)
2.当手动添加一个构造函数以后,会将默认的无参数的构造函数覆盖掉。
3.类的构造函数是不能被继承的。只能在子类中去调用父类的构造函数。
编译是为父类对象,但运行却是一个子类对象。具体特征如下:
1.被声明为父类对象
2.拥有父类属性
3.占用子类的内存空间
4.子类方法覆盖父类的方法时,此时对象调用的是子类的方法;否则,自动调用继承父类的方法.
抽象类和接口的区别
接口定义类的公共行为,抽象类定义类的公共实现
一个类只能继承自一个类(抽象类),但是可以同时实现多个接口
接口中不能有实现,抽象类中可以有未实现成员也可以有实现的成员
接口中未实现的方法必须在子类中实现,抽象类中未实现的成员必须在子类中重写
好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。
什么时候使用抽象类,什么时候使用接口
抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。
1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。
2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口
虚方法和抽象方法的区别
虚方法必须有实现(哪怕是空实现),抽象方法必须没有实现
抽象方法必须在抽象类中声明,虚方法可以出现在抽象类中
抽象方法必须在子类中重写,虚方法可以被重写
实现多态的主要手段:
1.虚方法virtual
2.抽象方法abstract
3.接口。
关于虚方法需要注意的几点:
1.父类中如果有方法需要让子类重写,则可以将该方法标记为virtual
2.虚方法在父类中必须有实现,哪怕是空实现。
3.虚方法子类可以重写(override),也可以不重写。
public abstract class MyBase { protected abstract void Search(); protected virtual void Save() { dbContent.SaveChange(); } }
static
class Program { static void Main(string[] args) { Person p = new Person(); p.Name = "张三"; Person.age = 18; Test t = new Test(); t.MyMethod(); Console.WriteLine(p.Name); Console.WriteLine(Person.age); Console.ReadKey(); } }
enum Gender { Male,Female}
把字符串转换成枚举Gender g = (Gender)Enum.Parse(typeof(Gender), "Male");
struct
就是小类,值类型,不能继承类,可以实现接口,不能有显示无参构造函数(隐式),除非字段被声明为 const 或 static,否则无法初始化.
结构体适合一些小型数据结构,这些数据结构包含的数据以创建结构后不修改的数据为主。例如:struct类型适于表示Point、Rectangle和Color等轻量对象。
由于结构的副本由编译器自动创建和销毁(结构必须要在实例化前对其内的成员变量进行初始化),因此不需要使用默认构造函数和析构函数。实际上,编译器通过为所有字段赋予默认值来实现默认构造函数。
String字符串的一些特性:
StringBuilder
Equals、==、ReferenceEquals方法
数组
Array是所有数组的父类。
System.Collections.Specialized 命名空间包含专用的和强类型的集合,例如,链接的列表词典、位向量以及只包含字符串的集合。
System.Collections.Concurrent 命名空间提供多个线程安全集合类。当有多个线程并发访问集合时,应使用这些类代替 System.Collections 和 System.Collections.Generic 命名空间中的对应类型。
键值对集合原理示意图
装箱、拆箱
必须是: 值类型→引用类型 或 引用类型→值类型。
拆箱时,必须用装箱时的类型来拆箱
文件操作常用相关类
using (StreamWriter writer = new StreamWriter(stream, encoding))
{
writer.WriteLine("你好");
}
面试题)深度拷贝。浅层拷贝。先手写浅层拷贝、深层拷贝的代码,理解了概念再谈用MemberwiseClone 、DeepCopy。见备注 写代码拷贝,实现ICloneable方法,内部调用MemberwiseClone 参考资料http://www.cnblogs.com/liping13599168/archive/2007/07/28/834242.html static object DeepCopy(object src) { BinaryFormatter Formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone)); using (MemoryStream stream = new MemoryStream()) { Formatter.Serialize(stream, src); stream.Position = 0; return Formatter.Deserialize(stream); } }
正则表达式
正则表达式是用来进行文本,字符串进行处理的技术,是语言无关的。
元字符
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
w | 匹配字母或数字或下划线或汉字 |
s | 匹配任意的空白符 |
d | 匹配数字 |
b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
代码/语法 | 说明 |
---|---|
W | 匹配任意不是字母,数字,下划线,汉字的字符 |
S | 匹配任意不是空白符的字符 |
D | 匹配任意非数字的字符 |
B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
分类 | 代码/语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成 (?'name'exp) | |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?<!exp) | 匹配前面不是exp的位置 | |
注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅 读 |
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的 字符。以这个表达式为例:a.*b,它将会匹配最长的以 a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的 字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提 下使用最少的重复。现在看看懒惰版的例子吧:
a.*?b匹配最短的,以a开始,以b结 束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另 一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins。
代码/语法 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
处理选项
在C#中,你可以使用Regex(String, RegexOptions)构造函数来设置正则表达式的处理选项。 如:Regex regex = new Regex(@"baw{6}b", RegexOptions.IgnoreCase);
上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项:
名称 | 说明 |
---|---|
IgnoreCase(忽略大小写) | 匹配时不区分大小写。 |
Multiline(多行模式) | 更改^和$的 含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的 精确含意是:匹配n之前的位置以及字符串结束前的位置.) |
Singleline(单行模式) | 更改.的含义,使它与每一个字符匹配(包括换行 符n)。 |
IgnorePatternWhitespace(忽略空白) | 忽略表达式中的非转义空白并启用由#标记的注释。 |
ExplicitCapture(显式捕获) | 仅捕获已被显式命名的组。 |
一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较 相似(以至于让人感到疑惑)以外。
代码/语法 | 说明 |
---|---|
a | 报警字符(打印它的效果是电脑嘀一声) |
b | 通常是单词分界位置,但如果在字符类里使用代表退格 |
t | 制表符,Tab |
r | 回车 |
v | 竖向制表符 |
f | 换页符 |
n | 换行符 |
e | Escape |
0nn | ASCII代码中八进制代码为nn的字符 |
xnn | ASCII代码中十六进制代码为nn的字符 |
unnnn | Unicode代码中十六进制代码为nnnn的字符 |
cN | ASCII控制字符。比如cC代表Ctrl+C |
A | 字符串开头(类似^,但不受处理多行选项的影响) |
Z | 字符串结尾或行尾(不受处理多行选项的影响) |
z | 字符串结尾(类似$,但不受处理多行选项的影响) |
G | 当前搜索的开头 |
p{name} | Unicode中命名为name的字符类,例如p{IsGreek} |
(?>exp) | 贪婪子表达式 |
(?<x>-<y>exp) | 平衡组 |
(?im-nsx:exp) | 在子表达式exp中改变处理选项 |
(?im-nsx) | 为表达式后面的部分改变处理选项 |
(?(exp)yes|no) | 把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为 此组的表达式;否则使用no |
(?(exp)yes) | 同上,只是使用空表达式作为no |
(?(name)yes|no) | 如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用 no |
(?(name)yes) | 同上,只是使用空表达式作为no |
Delegate
用委托可以指向任意的函数,哪怕之前没有定义------通过匿名方法去实现(只需要用一次的方法 ),写在主函数里,如DelString del=delegate(string str){return "\"“+str+"\"";};
线程就是一个委托
Event
委托和事件的区别(常考)
AppDomain.CurrentDomain.GetAssemblies()
反射
//命名空间 string nameSpace =System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace; //文件名 string className = Path.GetFileNameWithoutExtension(path); //类的全名称 string fullName = nameSpace+"."+className; System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName,true) ;
“生成此程序的程序集比加载的运行时新”,因为用Vs2008开发的主程序,但插件用的是Vs2010开发的。新建的时候选择.net3.5Framework就可以了。 public void ShutDown(string second) { Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.Start(); process.StandardInput.WriteLine("shutdown -s -f -t " + second); //process.StandardInput.WriteLine("dir c:"); process.StandardInput.WriteLine("exit"); process.Close(); } //通过接口定义 插件怎么去实现 public interface IPlugin { string PluginName { get; } string Execute(string param); } //窗体加载 void LoadMenu() { string path = AppDomain.CurrentDomain.BaseDirectory; path = Path.Combine(path, "Plugin"); string[] plugins = Directory.GetFiles(path,"*.dll"); foreach (string plugin in plugins) { Assembly ass = Assembly.LoadFile(plugin); foreach (Type t in ass.GetExportedTypes()) { //typeof(IPlugin).IsAssignableFrom(t)判断t这种类型是否实现了接口 if (typeof(IPlugin).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) { IPlugin ip = Activator.CreateInstance(t) as IPlugin; ToolStripItem tsi = TSMITools.DropDownItems.Add(ip.PluginName); tsi.Tag = ip; tsi.Click += new EventHandler(tsi_Click); } } } } void tsi_Click(object sender, EventArgs e) { ToolStripItem tsi = sender as ToolStripItem; IPlugin ip = tsi.Tag as IPlugin; if (ip != null) { string r = ip.Execute(textBox1.Text); if (!string.IsNullOrEmpty(r)) { MessageBox.Show(r); } } } //关机插件 public class Cmd:IPlugin { public string PluginName { get { return "关机插件"; } } public string Execute(string param) { ShutDown(param); return ""; } public void ShutDown(string second) { Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.Start(); process.StandardInput.WriteLine("shutdown -s -f -t " + second); //process.StandardInput.WriteLine("dir c:"); process.StandardInput.WriteLine("exit"); process.Close(); } } //字典插件 public class Dic:IPlugin { public string PluginName { get { return "字典插件"; } } public string Execute(string param) { return Translate(param); } public string Translate(string key) { Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("english", "英语"); dic.Add("chinese", "中文"); dic.Add("eat", "吃"); dic.Add("dog", "狗"); if (dic.ContainsKey(key)) { return dic[key]; } else { return null; } } }
Type type = typeof(Person); MethodInfo method = type.GetMethod("SayHi", BindingFlags.NonPublic | BindingFlags.Instance); object obj = Activator.CreateInstance(type); method.Invoke(obj, null); public class Person { private void SayHi() { Console.WriteLine("hi!"); } }
隐式类型(类型推断)
可以使用new关键字调用匿名初始化器创建一个匿名类型的对象。匿名类型直接继承自System. Object。
<![CDATA[ 文本 ]]>:<![CDATA[ 这里的文字将被解析为纯文本,即便有 < >的标签也不会被解析为xml标签。 ]]>
RSS是站点用来和其他站点之间共享内容的简易方式( 也叫聚合内容)。RSS使用XML作为彼此共享内容的标准方式。它代表了Really Simple Syndication(或RDF Site Summary,RDF站点摘要)。 它能让别人很容易的发现你已经更新了你的站点, 并让人们很容易的追踪他们阅读的 所有weblogs。
http://tech.163.com/special/000915SN/simplerss.html