请问NEW和USING的区别?
很多公司的面试都可能问或是考查这个看似基础的东西,恕我浑浑噩噩,我可能回答的不够好!习惯性质的是由于我可能知道一些东西,但由于事务缠身,并没有去过多的关注部分细节,其间也没有得到某些无意或是有意的灌输,我可能会回答区别在于一个不会自动释放资源,一个会。那USING为甚么会了?在甚么时候使用USING合适?等
我不知道在后面的回答是否都能把握的好,这只能说明我不够精通,但这些题目从来就没有给别人这样一个机会,假如你回答的不好,你是否能通过一种途径来找出区别,然后你再重新回答。
我笑了,假如我回答的不够好,我觉得后面是一个机会(也是一种能力的考察),我会通过甚么途径了,ILDASM,至少我知道我们生活再.NET的“蜜糖”中,我们有了好的高层次的框架,我有了很好的开发效率,但我忽视了细节,有很多时候,甚至懒得去关心细节,但这个题目让我觉得很丢脸,我回答的不好(阴沟里还翻了船) ,但我自知,秘密就藏再后面,于是我解开一段DEMO,看个明白。
namespace Demo
{
class Class1
{
[STAThread]
static void Main( string [] args)
{
Test obj1 = new Test();
using (Test obj2 = new Test())
{
}
}
}
class Test:System.IDisposable
{
int a;
public int Val
{
get
{
return a;
}
}
#region IDisposable Members
public void Dispose()
{
}
#endregion
}
}
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 25 (0x19)
.maxstack 1 ---推导堆栈
.locals init ([0] class Demo.Test obj1,
[1] class Demo.Test obj2) --定义了两局部变量
IL_0000: newobj instance void Demo.Test::.ctor()
IL_0005: stloc.0 -- 创建了Test对象并存放到 第一个局部量
IL_0006: newobj instance void Demo.Test::.ctor()
IL_000b: stloc.1 -- 创建了Test对象并存放到第二个局部量
.try
{
IL_000c: leave.s IL_0018 -- 你可以看作是GOTO语句 ,但是你要清楚,异常和RETURN,GOTO都不能逃出FINALLY,
} // end .try FINALLY是一定会执行
finally
{
IL_000e: ldloc.1 --载入局部量1,也是就我们用USING扩起的那个局部量)
IL_000f: brfalse.s IL_0017 --发现,如果这个对象是NULL的,就结束 ,否则就调用对象上的DISPOSE方法(),哦原来如此
IL_0011: ldloc.1 -- 我们终于发现了秘密,^_^,假如面试前你正好研究过,你回答的是否就更清晰!
IL_0012: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0017: endfinally
} // end handler
IL_0018: ret
} // end of method Class1::Main
现在我要回答后面的问题了,是框架帮我做了手脚,他强制帮我调用对象的DISPOSE资源释放方法,而且,如果你的对象没有实现此IDISPOSABLE接口,却用了USING,编译是不会通过的哟!这里看来,USING的时机是当对象使用了非托管资源或是比较宝贵的资源,
而对于托管的或非宝贵的资源,我可以依赖GC,没有必要自己画蛇添足。而且TRY块是会影响效率的。
请问FOREACH的机制是甚么?
哎!我就是用着爽嘛! 而且我几乎就把它当一个语法来看,谁又会没有刻意的却去看它的细节了,如果有的东东不清楚,我可以翻MSDN,我去GOOGLE搜,我自己看ILDASM,^_^,面试的人也不要因人家回答的不好就痞的人家一钱不值的样子(有这样的人,自命不凡而已)你非框架
的缔造者,微软的秘密多的去了,一个人是否能面面具到了,你是否就真的考察了能力,或只是换了皮囊的应试。希望这里也仍给人一个机会
找出这个机制,想想,我们访问一个ArrayList时,我用过,于是第二个DEMO出来
using System.Collections;
namespace Demo
{
class Class1
{
[STAThread]
static void Main( string [] args)
{
ArrayList arr = new ArrayList();
foreach ( object obj in arr)
{
}
}
}
}
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 50 (0x32)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.ArrayList arr, --我们的列表对象
[1] object obj, --FOREACH中用到临时量
[2] class [mscorlib]System.Collections.IEnumerator CS$00000006$00000000, --枚举器对象临时变量
[3] class [mscorlib]System.IDisposable CS$00000002$00000001) --这里我们看到定义了四个局部量
IL_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() --我构造了列表对象。
IL_0005: stloc.0 -- 存起
IL_0006: ldloc.0 -- 推入推导堆栈
IL_0007: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
IL_000c: stloc.2 // --我调用了GETENUMERATOR方法,它的作用是获得一个枚举器,这是你看到前面定义局部量还奇怪了
.try --进入TRY
{
IL_000d: br.s IL_0016 --无条件GOTO到IL_0016
IL_000f: ldloc.2 --MOVENET为真就会跳到这里来,这里仍需要枚举器对象,然后调用枚举器对象的GET_CURRENT方法获得遍历的对象
IL_0010: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0015: stloc.1 --将遍历的大的对象存到OBJ1中
IL_0016: ldloc.2 -- 载入变量2,变量2是个甚么东东,就是 TRY前的一句,得到的枚举器对象
IL_0017: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() --调用这个枚举器对象的MOVENET方法。
IL_001c: brtrue.s IL_000f --如果MOVENET返回假,表明已经遍历到头了,真表示仍可以遍历,真跳到IL_000F
IL_001e: leave.s IL_0031
} // end .try
finally
{
IL_0020: ldloc.2
IL_0021: isinst [mscorlib]System.IDisposable --看枚举器是否是一个IDISPOSABLE对象 就是 ENUMERATOR IS IDISPOSABLE
IL_0026: stloc.3
IL_0027: ldloc.3
IL_0028: brfalse.s IL_0030
IL_002a: ldloc.3
IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0030: endfinally
} // end handler
IL_0031: ret
} // end of method Class1::Main
我们看到一些非我们定义的东西,甚么枚举器呀,GETEnumerator()来获得枚举器等等,于是会让我想看看ARRAYLIST的
实现,它究竟是耍了什么花招可以有这些了,你看看类库的反编译代码,你就发现,这些集合类实现了一个接口,那就是
System.Collections.IEnumerable (可枚举) ,这个接口也没搞甚么,就是要你实现一个System.Collections.IEnumerator接口的 对象,经MSDN翻查
我看到这个IEnumerator接口就定义甚么MOVENET, GET_CURRENT之类的,接口协定了行为的约束集合,是为了让框架能够服务于此,框架控制
了流程,它调用了我们的代码,对于我们来说,框架如何使用我们的代码是透明的,真的觉得框架类似一个功能强大的中间件哈!。
于是乎,我们明白了,我们知道了FOREACH的机制 是你实现IEnumerable,IEnumetrtor接口,能够让我们的一些对象能够遍历自己的部分的一种
能力,而FOREACH仅是个伪装的代码,它甚至就是一个高级的宏!就是一个宏的机制,但需要我们对某些对象实现一些特定的接口,否则这个
宏如何起作用了^_^。
呵呵,清楚了吧,在我看到IL之前,或是我没有去关注过,我还真说不清楚FOREACH的机制(我只能搪塞),IDE是如何瞒天过海的做了那么多事情。
说到最后,好比封箱拆箱,C#代码表面都是糊弄着我们,没人教你,你不看IL你能知道吗,我们决不要学人云亦云的人(知其所以然)
面试的过程不是简单的质检,你要给别人机会,那就是如果你不清楚,你会如何,或打算怎么去弄清楚,解决的途径,而
非一个绝对的答案。你应该学会接受这样的答案 (我对FOREACH不清楚,但是我会怎么样就可以怎么样去了解它。。。)
看别人对问题的态度和处理方式,在纸上写一个算法思路还可以,写个运行的程序,最是无趣了!
注:本人水平有限,文中如有错误或不当之处 ,难免^_^