MS开发者应懂得知识
1、 假如在.NET里面要用其他程序的.dll文件该怎么做?
1.项目-引用-找到dll文件,添加
2.命名空间引用
2、 模态和非模态窗体的区别?
模态对话框在显示之后,就不能对同一个程序中的其它窗口进行操作,.NET Winform程序里面的ShowDialog()。
非模态对话框在显示之后,还可以对同一个程序的其它窗口进行操作,.NET Winform程序里面的Show()。
3、 解释一下.NET里面的GC的工作机制?
(转)第一个就是很多人用.Net写程序,会谈到托管这个概念。那么.Net所指的资源托管到底是什么意思,是相对于所有资源,还是只限于某一方面资源?很多人对此不是很了解,其实.Net所指的托管只是针对内存这一个方面,并不是对于所有的资源;因此对于Stream,数据库的连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到.Net管理而统称为非托管资源。而对于内存的释放和回收,系统提供了GC-Garbage Collector,而至于其他资源则需要手动进行释放。
那么第二个概念就是什么是垃圾,通过我以前的文章,会了解到.Net类型分为两大类,一个就是值类型,另一个就是引用类型。前者是分配在栈上,并不需要GC回收;后者是分配在堆上,因此它的内存释放和回收需要通过GC来完成。GC的全称为“Garbage Collector”,顾名思义就是垃圾回收器,那么只有被称为垃圾的对象才能被GC回收。也就是说,一个引用类型对象所占用的内存需要被GC回收,需要先成为垃圾。那么.Net如何判定一个引用类型对象是垃圾呢,.Net的判断很简单,只要判定此对象或者其包含的子对象没有任何引用是有效的,那么系统就认为它是垃圾。
明确了这两个基本概念,接下来说说GC的运作方式以及其的功能。内存的释放和回收需要伴随着程序的运行,因此系统为GC安排了独立的线程。那么GC的工作大致是,查询内存中对象是否成为垃圾,然后对垃圾进行释放和回收。那么对于GC对于内存回收采取了一定的优先算法进行轮循回收内存资源。其次,对于内存中的垃圾分为两种,一种是需要调用对象的析构函数,另一种是不需要调用的。GC对于前者的回收需要通过两步完成,第一步是调用对象的析构函数,第二步是回收内存,但是要注意这两步不是在GC一次轮循完成,即需要两次轮循;相对于后者,则只是回收内存而已。
那么对于程序资源来说,我们应该做些什么,以及如何去做,才能使程序效率最高,同时占用资源能尽快的释放。前面也说了,资源分为两种,托管的内存资源,这是不需要我们操心的,系统已经为我们进行管理了;那么对于非托管的资源,这里再重申一下,就是Stream,数据库的连接,GDI+的相关对象,还有Com对象等等这些资源,需要我们手动去释放。
如何去释放,应该把这些操作放到哪里比较好呢。.Net提供了三种方法,也是最常见的三种,大致如下:
<!--[if !supportLists]-->1. <!--[endif]-->析构函数;
<!--[if !supportLists]-->2. <!--[endif]-->继承IDisposable接口,实现Dispose方法;
<!--[if !supportLists]-->3. <!--[endif]-->提供Close方法。
经过前面的介绍,可以知道析构函数只能被GC来调用的,那么无法确定它什么时候被调用,因此用它作为资源的释放并不是很合理,因为资源释放不及时;但是为了防止资源泄漏,毕竟它会被GC调用,因此析构函数可以作为一个补救方法。而Close与Dispose这两种方法的区别在于,调用完了对象的Close方法后,此对象有可能被重新进行使用;而Dispose方法来说,此对象所占有的资源需要被标记为无用了,也就是此对象被销毁了,不能再被使用。例如,常见SqlConnection这个类,当调用完Close方法后,可以通过Open重新打开数据库连接,当彻底不用这个对象了就可以调用Dispose方法来标记此对象无用,等待GC回收。明白了这两种方法的意思后,大家在往自己的类中添加的接口时候,不要歪曲了这两者意思。
GC为了提高回收的效 率使用了Generation的概念,原理是这样的,第一次回收之前创建的对象属于Generation 0,之后,每次回收时这个Generation的号码就会向后挪一,也就是说,第二次回收时原来的Generation 0变成了Generation 1,而在第一次回收后和第二次回收前创建的对象将属于Generation 0。GC会先试着在属于Generation 0的对象中回收,因为这些是最新的,所以最有可能会被回收,比如一些函数中的局部变量在退出函数时就没有引用了(可被回收)。如果在Generation 0中回收了足够的内存,那么GC就不会再接着回收了,如果回收的还不够,那么GC就试着在Generation 1中回收,如果还不够就在Generation 2中回收,以此类推。Generation也有个最大限制,根据Framework版本而定,可以用GC.MaxGeneration获得。在回收了内存 之后GC会重新排整内存,让数据间没有空格,这样是因为CLR顺序分配内存,所以内存之间不能有空着的内存。现在我们知道每次回收时都会浪费一定的CPU 时间,这就是我说的一般不要手动GC.Collect的原因(除非你也像我一样,写一些有关GC的示例!^_^)。
4、 什么时候进行垃圾回收?
对象或者其包含的子对象没有任何引用时
5、 垃圾回收分几步?
GC对于前者的回收需要通过两步完成,第一步是调用对象的析构函数,第二步是回收内存,但是要注意这两步不是在GC一次轮循完成,即需要两次轮循;相对于后者,则只是回收内存而已。
6、 Finalize机制
由于Dispose方法的调用依赖于使用者,为了弥补这一缺陷,.NET同时提供了Finalize方法。Finalize方法通常被具有C++开发经验的程序员称为析构方法,但它的执行方法却和传统C++中的析构函数完全不同。Finalize方法在GC执行垃圾回收时调用,具体的机制是这样的:
- 当每个包含Finalize方法的类型的实例对象被分配时,.NET会在一张特定的表中添加一个引用并且指向这个实例对象。方便起见起见就称该表为“带析构对象表”。
- 当GC执行并且检测到一个不被调用的对象时,需要进一步检查“带析构对象表”来查看该对象类型是否具有Finalize方法,如果没有则该对象被视为垃圾,如果存在Finalize方法,则把该对象的引用从“带析构对象表”移动到另外一张表中,这里暂时称它为“等待析构表”。并且该对象实例被视为仍然在被使用。
- CLR酱油一个单独的线程负责处理“等待析构表”,其方法就是一次通过引用调用其中每个对象的Finalize方法,然后删除引用,这是托管堆(DebugLZQ特别提醒,注意:.NET中的垃圾回收,就是释放这个堆上不再被使用的内存对象(因为引用类型的对象存放在这个堆上)。注意区分堆栈,堆栈存放的是值类型对象和托管堆上引用类型对象的指针。)中的对象实例被认为处于不在被使用的状态。
- 在下一个GC执行时,将释放已经被调用Finalize方法的那些对象实例。
警告:Finalize方法应该只致力于快速而简单地释放非托管资源,并且尽可能快地返回。不正确的Finalize方法可能包含这样的代码:
- 没有保护地写文件日志
- 访问数据库
- 访问网络
- 当前对象被付给某个存活的引用
当Finalize方法试图访问文件系统、数据库系统或者网络时,将会有资源争用和等待的潜在危险。试想一个不断尝试访问离线数据库的Finalize方法,将会在长时间内不会反回,这不仅影响了对象本省的释放,也使得排在Finalize方法队列中的所有后续对象得不到释放,这个连锁反应将很快造成内存耗尽(结果是死机,最近DebugLZQ在医生站项目中就曾遇到了这个情况!!!)。
而另外一种危险的代码是在Finalize方法中把对象自身又赋值给另外一个存活的引用,这时对象内的一部分资源已经被释放了,而另外一部分则没有,这样一个对象再被激活后,将导致不可预知的后果。
public class FinalizeDisposeBase : IDisposable
{ // 标记对象是否已被释放
private bool _disposed = false;
// Finalize方法:
~FinalizeDisposeBase()
{ Dispose(false); }
// 这里实现了IDispose中的 Dispose方法
public void Dispose()
{ Dispose(true);
//告诉GC此对象的Finalize方法不再需要调用
GC.SuppressFinalize(this);
}
//在这里做实际的析构工作
//申明为虚方法以供子类在有必要时重写
protected virtual void Dispose(bool isDisposing)
{ // 当对象已经被析构时,不再执行
if (_disposed) return;
if (isDisposing)
{ //在这里释放托管资源
//只在用户调用Dispose方法时执行
}
//在这里释放非托管资源
//标记对象已被释放
_disposed = true;
}
}
public sealed class FinalizeDispose : FinalizeDisposeBase
{
private bool _mydisposed = false;
protected override void Dispose(bool isDisposing)
{ // Don't dispose more than once.
if (_mydisposed) return;
if (isDisposing)
{
//在这里释放托管的并且在这个类型中申明的资源
}
//在这里释放非托管的并且在这个类型中申明的资源
//调用父类的Dispose方法来释放父类中的资源
base.Dispose(isDisposing);
// 设置子类的标记 _mydisposed = true;
}
7、 GAC?
全称是Global Assembly Cache作用是可以存放一些有很多程序都要用到的公共Assembly,例如System.Data、System.Windows.Forms等等。这样,很多程序就可以从GAC里面取得Assembly,而不需要再把所有要用到的Assembly都拷贝到应用程序的执行目录下面。举例而言,如果没有GAC,那么势必每个WinForm程序的目录下就都要从C:\WINDOWS\Microsoft.NET\Framework\vX下面拷贝一份System.Windows.Forms.dll,这样显然不如都从GAC里面取用方便,也有利于Assembly的升级和版本控制。
8、 Generic泛型
9、 堆栈和托管堆的区别。
分别对应值类型和引用类型的在内存上的分配方式,前者不需要被GC回收。
10、 Property和attribute
1.Property:
Property可以说是一个面向对象的概念,提供了对私有字段的访问封装,在C#中以get和set访问器方法实现对可读可写属性的操作,提供了安全和灵活的数据访问封装。比如:
- public class Robot
- {
- private string name = ""; //字段:Field
- public string Name //属性:Property,对Field进行封装。
- {
- get { return name; }
- set { name = value; }
- }
- }
2.Attribute:
Attribute的目标是:运行时为元素提供附加信息。它的作用更类似于注释。
可以说,Property/Field和Attribute是两个完全不同的概念,虽然他们有些时候能做一样的事,但请记住,他们是从本质上就不同的两个东西。
11、 C#里面可以使用指针吗?(委托)
1.项目-属性-Build-Allow unsafe code
2. unsafe{//code}
http://www.cnblogs.com/xiaotie/archive/2012/07/06/2579853.html
12、 Appdomain
一个应用程序在其中执行的独立环境”。为执行托管代码提供隔离、卸载和安全边界。http://technet.microsoft.com/zh-cn/subscriptions/system.appdomain
微软的.NET文档中appDomain的解释相当简略(却不是很清楚J): “一个应用程序在其中执行的独立环境”。为执行托管代码提供隔离、卸载和安全边界。到底如何理解呢?我想是不是可以这样来准确体会这个概念:
1、appDomain是.NET框架独有的概念。找不到其他技术体系中贴切的参照概念,是微软自己的东东。很多人认为可以同进程的概念相同,我很不赞同:其一,“进程”是操作系统中的概念,在虚拟机/框架之类的体系中有着自己的定义和功能,显然这样理解appDomain是错误的;其二,“在应用程序域和线程之间没有一对一的关联,多个线程可以属于一个应用程序域,尽管给定的线程并不局限于一个应用程序域,但在任何给定时间,线程都在一个应用程序域中执行。”(.NET FrameWork SDK 中的描述),如果这里的“应用程序域”换成“进程”讲得通么?
2、隔离性。也不怪有人直接套解为进程,AppDomain有着代码执行隔绝的特性,就好像进程做的一样。appDomain的对象、代码可以认为相互隔离,甚至一个appDomain中的代码调用另外appDomain的对象(的数据或者方法等),需要类似DCOM中的“列集/散集”才可以进行(在类继承关系中appDomain类 继承自 MarshalByRefObject类)。每一个appDomain可以单独被调试、启动、停止,有着自己的默认的异常处理,一个appDomain崩溃了,不会影响其他的appDomain。可以理解为.NET的“逻辑进程”。
.NET中允许同一个应用程序的不同版本可以并存,消除了所谓的“dll hell”。通过创建不同的appDomain,我们可以让某个托管的程序集的1.0和2.0的版本同时执行(只要他们自身并不存在某个特定资源的非兼容性的存取访问)
3、安全性。由于代码隔离,可以防止某个危险代码对于其他的appDomain的影响。而且可以通过分配特定的安全分配,确定appDomain中的执行代码对于系统安全保护资源的访问。
4、独立性。每一个appDomain都由.NET的框架分配了专用的存储区(应用域局部存储)。任何对象都可以访问自己当前所在的appDomain的局部存储区,这个局部存储区被整个appDomain中的对象共享,也包括进入appDomain的线程(运行于同一个appDomain的线程可以通过这个局部存储进行通信)。
5、同进程、线程、程序集的关系。同进程属于多对一的关系,即一个进程中可以有多个appDomain,但是appDomain只能存在于某个进程中(显然,正如同上文:进程同appDomain属于不同的概念)。缺省情况下,如果你没有自己创建多个appDomain,一个进程启动后自动创建一个appDomain。而线程执行可以涉及多个appDomain,但某个特定时刻,线程仅存在于一个appDomain中,且线程可以进入其他的appDomain。某个程序集的某个实例属于具体的appDomain,由appDomain在自己的范围内加载,并按照程序集创建相应的对象。AppDomain是程序集的执行环境,同时程序集作为静态实体,可以被多个appDomain加载执行。
很多人文章讲了相关的编程(但没有将清楚什么是appDomain),鄙人也不想抄,基本上涉及appDomain的创建、卸载、获得当前appDomain实例、操作appDomain、appDomain中创建对象调用对象、加载特定程序集、执行程序、appDomain之间协调(回调、事件等)。可以参考我收集的一些URL:
appDomain参考
http://tech.ccidnet.com/pub/article/c1136_a30763_p1.html
http://www.yesky.com/SoftChannel/72342380484755456/20030819/1722679_2.shtml
http://www.microsoft.com/china/msdn/library/dncscol/html/csharp05162002.asp
http://wwwb.pconline.com.cn/pcedu/empolder/gj/vb/doc/10712_2.htm
http://www.csdn.net/Develop/Read_Article.asp?Id=19285
http://www.csdn.net/Develop/Read_Article.asp?Id=13303
SDK文档中的参考:
ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfsystemappdomainclasstopic.htm
ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfsystemappdomainmemberstopic.htm
通过前面讨论知道,其实在一般情况下我们是不需要理会appDomain的,不过,出现此概念在.NET中决非多余,有着自己存在的理由,那么具体载那些情境下要使用appDomain呢?
1、 需要隔离的程序集,譬如一些特别容易引起崩溃的代码可以考虑单独运行于一个特定的appDomain
2、 不同安全级别的程序集,如果需要为自己的代码划分安全执行的边界,可以考虑将不同安全级别的代码单独创建于某个设定了不同安全信息的appDomain
3、 从性能上考虑,有些程序集可能会消耗大量资源,尽管在托管环境下,基本上不存在资源消耗漏洞,但是总会存在特定时间访问密集造成消耗大量资源的情况,这时可以考虑创建单独的appDomain,在资源消耗超过临界点后进行appDomain的卸载,适应系统运行要求。Asp.net中利用不同得appDomain来提供支持就是为了防止一个应用程序的崩溃影响其他asp.net应用程序,同时,在不重新启动的系统不重新启动IIS不影响asp.net自身服务提供的情况下将一个appDomain卸掉同时启动新的appDomain,理想情况下可以实现web系统的长时间在线(这以往是昂贵的unix的特性,终于被MS“借鉴”了)。
4、 不同版本的同一应用程序集的同时运行。这个在COM时代是一个大问题,现在通过appDomain,实现了在一个进程中执行版本不同的两个程序集,可以做到良好的兼容性。
5、动态加载一些程序。
13、 在应用程序域A里面怎么调用应用程序域B 里面的方法
http://paxhujing.blog.163.com/blog/static/20190212020128182622777/
C++
1、 内联函数
2、 重载
3、 友元
4、 <>和””
5、 类和结构体区别
6、 类和结构体里面默认的访问权限是什么?
7、 进程和线程的区别
8、 进程间如何通信
9、 线程如何实现同步
10、 虚函数
11、 堆和栈的区别
12、 程序里面如何实现虚拟内存(不是操作系统的虚拟内存)
数据库:
1、 如何获取表的列信息或是列数
2、 怎么调用存储过程
3、 SQL有几种认证方式分别是什么?
4、 DataReader和DataSet?
本文来自博客园,作者:NLazyo,转载请注明原文链接:https://www.cnblogs.com/bile/archive/2013/01/18/2866826.html