父类构造方法中调用虚方法
摘要:1、在C++中,明确指出,不要在父类构造方法调用虚方法,为啥? 因为,构造子类对象,首先调用父类构造方法(初始化列表,然后构造方法内代码),然后子类构造方法(初始化列表,然后构造方法内代码),在父类构造方法中,还没有子类的成分,也就是说,当前本质上还是父类对象。因此,调用的方法还是父类方法,不会产生预期的多态行为。2、但是,最近在C#当中发现一个很奇怪的现象:父类构造方法调用虚方法,也会产生多态的行为。确实让人奇怪,只能说编程语言细节太多。C#是如何做到的呢? 自己猜测,可能是在父类构造方法之前,完成了对虚方法表的整体拷贝,并且置换为重写后的方法。
阅读全文
posted @
2014-03-06 20:45
Andy Niu
阅读(1260)
推荐(0) 编辑
理解C# Lazy<T>
摘要:1、Lazy解决什么问题? 考虑下面的需求,有个对象很大,创建耗时,并且要在托管堆上分配一大块空间。我们当然希望,用到它的时候再去创建。也就是延迟加载,等到真正需要它的时候,才去加载。考虑一下,我该怎么解决这个问题。2、显然,这里需要加一个中间层,将大对象封装起来,暴露接口,开始并不创建大对象,等到用户真正访问对象的时候,再去创建。另外,这个中间层应该可以封装不同类型的大对象,因此需要类模版。Lazy就是为了解决这个问题。
阅读全文
posted @
2014-01-15 20:46
Andy Niu
阅读(2825)
推荐(1) 编辑
理解C# Attribute
摘要:1、Attribute与Property Attribute是特性,Property是属性。2、Attribute与注释 注释:是给程序员看的,编译的时候会去掉这些信息,也就是说,程序集中没有注释的内容。 Attribute:会被编译到程序集中,在程序集的元数据中,在加载程序集的时候,可以从它的元数据中提取出这些信息。3、说了那么多,考虑下,它解决什么问题? 考虑下面的需求,一个工具类提供了很多静态方法,甲乙两个程序员合作完成,理所当然,应该标识出哪些是甲写的,哪些是乙写的,用于统计。最笨的加注释,但是它有两个问题:a、编译后生成的程序集中,没有了这些注释内容;b、只能通过人工去统计甲...
阅读全文
posted @
2014-01-14 20:46
Andy Niu
阅读(2203)
推荐(2) 编辑
理解 MEF
摘要:1、它解决什么问题? 考虑下面的需求,甲程序员对外暴露接口,内部提供实现。乙程序员使用甲提供的接口,根据面向接口编程的原则,乙关联一个接口类型的引用。正常情况下,乙要使用甲的实现,必须实例化一个具体对象。有没有更好的办法呢?我们知道Java框架spring中有个依赖注入的概念。C#中能不能使用类似的方式呢?2、怎么解决? 使用MEF(Managed Extensibility Framework),示例如下: 1 namespace TestMEF 2 { 3 public interface IBookService 4 { 5 void GetBookN...
阅读全文
posted @
2014-01-14 20:16
Andy Niu
阅读(469)
推荐(0) 编辑
C# explicit与implicit
摘要:1、它们解决什么问题? 考虑下面的需求,Person类有个字段age。我想使用Person p = (Person) 18 来创建一个age为18的Person对象,怎么办? 更进一步,我想使用Person p = 18 来创建一个age为18的Person对象,怎么办?2、使用explicit(显式)和implicit(隐式) 1 class Person 2 { 3 private int age; 4 public int Age 5 { 6 get { return age; } 7 ...
阅读全文
posted @
2014-01-14 19:55
Andy Niu
阅读(2892)
推荐(2) 编辑
C# is与as
摘要:1、使用场景: 强制类型转换,有可能会导致异常。is与as就是为了解决这一问题,is与as永远不会抛出异常。2、is判断一个对象是否兼容于指定的类型,考虑里氏代换。Dog是Animal,而Animal不是Dog。3、as 与强制类型转换一样,区别是使用as是安全的。使用as如果转换失败,返回Null,不会抛出异常。4、使用is和as可以取代强制类型转换,分别如下: 1 a、使用is 2 if(a is Dog) 3 { 4 Dog d = (Dog)a; 5 ... 6 } 7 8 b、使用as 9 Dog d = a as Dog;10 if(d!...
阅读全文
posted @
2013-11-26 18:34
Andy Niu
阅读(3600)
推荐(0) 编辑
VS DLL 复制本地
摘要:1、引用一个DLL,需要指定路径,复制本地的意思是 把这个DLL复制到exe的Debug目录(调试的时候)。2、复制到本地的动作是在生成的时候执行的,清理的时候会删除。3、从外部引用一个DLL,不复制到本地,生成没问题,运行会报错,因为,Debug目录没有DLL。4、每次清理会删除Debug目录的DLL,重新生成会再次复制到Debug目录,为了避免这种情况,可以:把DLL放到Debug目录,直接引用Debug目录下的DLL,同时复制本地设为false5、如果引用一个工程,复制本地必须要设置为true,只有这样,修改工程导致的结果才能体现出来。同时,引用一个工程,这个工程会把自己所需要的DLL,
阅读全文
posted @
2013-11-21 18:23
Andy Niu
阅读(7090)
推荐(0) 编辑
C# String.Format
摘要:C货币string.Format("{0:C3}", 2)$2.000D十进制string.Format("{0:D3}", 2)002E科学计数法1.20E+0011.20E+001G常规string.Format("{0:G}", 2)2N用分号隔开的数字string.Format("{0:N}", 250000)250,000.00X十六进制string.Format("{0:X000}", 12)Cstring.Format("{0:000.000}", 12.2)0
阅读全文
posted @
2013-11-08 14:08
Andy Niu
阅读(780)
推荐(0) 编辑
理解MVVM模式
摘要:1、WPF的核心是数据绑定。2、考虑这样一个场景:界面上有一个TextBox显示Person的年龄,一个Button,点击一次Button,年龄加1。3、做一个View,上面有TextBox和Button,TextBox的Text绑定ViewModel中Person的年龄,Button的Command绑定ViewModel中的命令。4、设置View的DataContext为ViewModel5、ViewModel关联Person和Command对象,这里的Person就是Model。ViewModel对View暴露两个接口:Person的Age和Command。6、Command封装Perso
阅读全文
posted @
2013-10-25 18:55
Andy Niu
阅读(323)
推荐(0) 编辑
我的编码规范(慢慢补充)
摘要:一、变量1、集中使用变量,比如:1 int a = 1;2 ...3 ...4 a = a*2+1; 修改为1 int a =1;2 a = a*2+1;3 ...4 ...2、全局变量的取舍 全局变量的优点:可以随时随地使用,方便。 全局变量的缺点:多地使用,可能会起冲突,其他人可能会破坏变量的内容。 优先使用局部变量,如果某个变量在方法中传来传去,成为流浪数据(tramp data),考虑使用全局变量。3、一个变量只有一个用途,也就是说,变量名在其生命周期中,只代表一个意思。4、千万不要使用文本常量(magic number),尽可能使用具名常量。5、使用CLR属性对字段封装,就暗...
阅读全文
posted @
2013-09-09 09:48
Andy Niu
阅读(330)
推荐(0) 编辑
lock
摘要:C# lock可以锁一个语句块,访问这个语句块的时候,大家排队,一个一个来。C# lock也可以锁多个语句块,多个语句块之间都互斥,访问这些语句块中的任意一个,都要一个一个来。
阅读全文
posted @
2013-09-07 17:34
Andy Niu
阅读(317)
推荐(0) 编辑
理解 WPF Dispatcher
摘要:解决的问题:一个应用程序是一个进程,一个进程包含几个线程,其中有一个是主线程,其余的是工作线程。在WPF应用程序中,主线程负责接收输入、处理事件、绘制屏幕等工作,为了使主线程及时响应,用户创建一些工作线程,工作线程做一些耗费时间和资源的事情,比如解码和接受网络数据。这里存在一个问题,由于UI元素是主线程创建的,工作线程不能更新主线程维护的UI元素的显示。DIspatcher就是解决这个问题的。如何解决问题:通过调用主线程的Dispatcher,执行Invoke (同步)或者BeginInvoke方(异步)方法,比如public delegate void NextPrimeDelegate()
阅读全文
posted @
2012-10-18 20:48
Andy Niu
阅读(3911)
推荐(1) 编辑
理解 IEnumerable 与 IEnumerator
摘要:我们在编码中,经常使用foreach遍历集合,能够遍历的集合必定实现了 IEnumerator接口,IEnumerator接口如下: 1 public interface IEnumerator 2 { 3 // 方法 4 //移到集合的下一个元素。如果成功则返回为 true;如果超过集合结尾,则返回false。 5 bool MoveNext(); 6 // 将集合设置为初始位置,该位置位于集合中第一个元素之前 7 void Reset(); 8 9 // 属性:获取集合中的当前元素10 object Cur...
阅读全文
posted @
2012-08-15 16:50
Andy Niu
阅读(255)
推荐(0) 编辑
理解委托
摘要:1、委托是优化的观察者模式观察者模式定义了一种一对多的关联关系,subject维护一个observer的集合,每个observer 内部引用subject,每次当subject发生变化,subject 遍历observer集合,通知observer 进行更新。实际上,为了面向抽象编程,会引入抽象subject和抽象observer,这里为了简单说明,就忽略抽象subject和抽象observer。观察者存在的问题:1、 要求observer具有相同的父类,但现实中,observer可能是风马牛不相及的类。2、 observer更新的方法名相同,但现实中,observer的更新方法名也可能不同。
阅读全文
posted @
2012-08-13 14:58
Andy Niu
阅读(394)
推荐(0) 编辑
理解泛型
摘要:泛型分为以下几类:1、泛型类:指定类中的字段为T,方法就是操作T类型的参数。2、泛型接口:指定接口中操作T类型的参数。3、泛型方法:操作T类型的参数。4、泛型委托:委托操作T类型的参数。T是类型参数,泛型的约束就是针对类型参数T进行约束。List<T> 是开放类型,不允许实例化,类似于接口。List<string>是封闭类型,每个封闭类型都有自己的静态成员。而且需要注意的是,List<string>与List<int>是两个毫无关系的类型。List<T>继承Object,List<string>和List<int&g
阅读全文
posted @
2012-08-10 12:03
Andy Niu
阅读(226)
推荐(0) 编辑
C# 理解 abstract、virtual、override
摘要:abstract、virtual、override三个关键字涉及到继承,采用父亲和儿子类比。abstract : 父亲告诉儿子,我只是声明要做这个事情,自己没有做,所以你必须去做这个事情。virtual : 父亲告诉儿子三种情景,a) 这个事情我做了,如果你满意的话,就不需要做了,直接继承就好了;b) 这个事情我做了,如果你有些不满意,可以在我的基础上,修改一下(使用override重写);c) 这个事情我做了,如果你非常不满意,就自己重新做一遍吧(使用new 隐藏父亲的实现)。override : 父亲使用virtual修饰方法,儿子对父亲做的事情不满意,在父亲的基础上,使用override
阅读全文
posted @
2012-08-10 11:34
Andy Niu
阅读(285)
推荐(0) 编辑
C# ref,out
摘要:ref 的使用场景:调用方法传递参数的时候,对于值类型是“整体拷贝”,在方法的修改只在方法内有效,方法结束,从栈上弹出。在方法外不会产生副作用。ref 就是针对这种情况设计的,ref修饰的参数,强制参数按引用传递,在方法内的修改产生副作用。out 的使用场景:与ref 类似。ref 与 out的区别在于:1、ref 必须在方法调用前,进行显式的初始化。2、out 不需要再方法调用前进行初始化,但是在方法返回之前,必须完成赋值操作。方法定义和方法调用的地方,都必须显式地使用关键字ref 或者out,ref 与 out的实现原理应该是 对值类型进行了装箱。
阅读全文
posted @
2012-01-10 14:57
Andy Niu
阅读(323)
推荐(0) 编辑