C#潜在面试问题……太难了?

如果不运行此代码,请确定将调用哪个Foo方法:

 class A { public void Foo( int n ) { Console.WriteLine( "A::Foo" ); } } class B : A { /* note that A::Foo and B::Foo are not related at all */ public void Foo( double n ) { Console.WriteLine( "B::Foo" ); } } static void Main( string[] args ) { B b = new B(); /* which Foo is chosen? */ b.Foo( 5 ); } 

哪种方法? 为什么? 运行代码不会作弊。

我在网上发现了这个难题; 我喜欢它,我想我会把它用作面试问题……意见?

编辑:我不会判断候选人是否错了,我会用它作为一种方式来开展关于C#和CLR本身的更全面的讨论,这样我就可以很好地理解候选人的能力。

资料来源: http //netpl.blogspot.com/2008/06/c-puzzle-no8-beginner.html

我真的不会用这个作为面试问题。 我知道答案及其背后的原因,但是这样的事情应该很少出现,这应该不是问题。 知道答案真的并没有表明候选人的编码能力。

请注意,即使A.Foo是虚拟的并且B覆盖它,您也会获得相同的行为。

如果你喜欢C#拼图和古怪, 我也有一些(包括这个) 。

太难? 不,但问题的目标是什么? 你期望从你的受访者那里得到什么? 他们知道这个特殊的句法怪癖吗? 这要么意味着他们已经很好地研究了规范/语言(对他们有利),要么他们遇到了这个问题(希望不是他们写的东西,但是如果他们这样做的话)。 这两种情况都没有真正表明你手上有一个可靠的程序员/工程师/建筑师。 我认为重要的不是问题,而是围绕这个问题的讨论。

当我采访候选人时,我通常会问一个基于语言语义怪癖的看似简单的问题 – 但是我不在乎我的受访者是否知道它,因为语义怪癖让我开辟了许多途径让我找到如果我的候选人是有条不紊的,他们的沟通方式,如果他们愿意说“我不知道”,他们是否有能力自我思考,他们是否理解语言设计和机器架构,他们是否理解平台和便携性问题 – 简而言之,我正在寻找许多成分,这些成分加起来“他们得到了吗?”。 此过程需要一个小时或更长时间。

最后,我实际上并不关心他们是否知道我的问题的答案 – 问题是让我间接得到所有其他信息而不必询问的诡计。 如果你在这个问题中没有一个有价值的优点,那就不要费心了 – 你在浪费时间和候选人的时间。

不能在那里与乔尔达成一致。 我有20多年的设计和编码经验,当我看到它时,我想到的第一件事就是:它甚至不会编译。

我做了这个假设,因为我试图避免只有一种数据类型不同的重载,并且在查看代码时甚至没有获得int / double差异; 我假设需要一个新的运算符来允许在B中重新定义。

事实上,我使用了一个库,一个程序员为处理一些文本文件生成而创建,这有点令人困惑,因为其中一个方法有8个不同的重载,其中两个只有最后一个参数的数据类型不同。 一个是字符串,一个是char。 参数的字符串版本所需的值是一个字符长度的可能性非常好,所以希望你能看到它的发展方向。 我们有一个时间调试问题的恶魔,因为库的消费者无意中触发了错误的调用,因为引用了差异,单一与双重。

故事的道德,感谢候选人不知道答案,因为它可能表明良好的编码习惯。

另一次投票反对使用它,但出于不同的原因。

当像这样放在现场时,许多非常优秀的程序员会提出错误的答案,但不是因为他们不知道这些概念或无法弄明白。 会发生什么事情,他们会看到这样的事情,然后思考,“啊哈,技巧问题!”,然后继续思考自己的反应。 在面试环境中尤其如此,他们没有IDE或Google或其他任何其他帮助程序员在日常编程中认为理所当然的好处。

Console.WriteLine(“B :: Foo”);

因为它将自动转换并使用第一个而不进一步inheritance。

我不认为这是一个很好的面试问题,但尝试解决而不编译代码会很有趣。

作为面试问题并不公平,因为这是一个棘手的问题。 我希望受访者得到的好答案更像是“那需要重构”

除非您希望雇用某人从事编译器工作,否则我不确定您是否需要深入了解CLR。

对于面试问题,我会寻找能够在答案中显示编码人员理解水平的内容。 这更像是一个奇怪/谜题。

这实际上是一个棘手的问题。

对于“应该”发生的事情,答案是模棱两可的。 当然,C#编译器将其从具体模糊性的范围中解脱出来; 但是,由于这些方法彼此重载,并且既不是覆盖也不是阴影,所以可以合理地假设“最佳参数拟合”应该适用于此,因此得出结论:应该是A :: Foo(int n)在提供整数作为参数时调用。

为了certificate“应该”发生的事情还不清楚,在VB.NET中运行时完全相同的代码会产生相反的结果:

 Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click Dim b As New B b.Foo(5) ' A::Foo b.Foo(5.0) ' B::Foo End Sub End Class Class A Sub Foo(ByVal n As Integer) MessageBox.Show("A::Foo") End Sub End Class Class B Inherits A Overloads Sub Foo(ByVal n As Double) MessageBox.Show("B::Foo") End Sub End Class 

我意识到我正在为C#程序员打开“bash”VB.NET而不遵守C#的机会。 但我认为人们可以提出一个非常强烈的论点,即VB.NET正在这里做出正确的解释。

此外,C#IDE中的IntelliSense建议B类有两个重载(因为有,或者至少应该是!),但实际上不能调用B.Foo(int n)版本(不是没有第一个)显式地转换为A)类。 结果是C#IDE实际上与C#编译器不同步。

另一种看待这种情况的方法是C#编译器正在进行预期的重载并将其转换为阴影方法。 (这对我来说似乎不是正确的选择,但这显然只是一种意见。)

作为一个面试问题,我认为如果你有兴趣在这里讨论这些问题就可以了。 至于让它“正确”或“错误”,我认为这个问题接近一个技巧问题,这个问题可能很容易被错过,甚至是错误的原因。 事实上,问题“应该是”的答案实际上是非常值得商榷的。

我认为这是一个可怕的问题。 我认为任何问题都是一个可怕的问题,当真正的答案是“运行它,看看!”

如果我需要在现实生活中了解这一点,那正是我要做的:创建一个测试项目,将其键入,然后找出答案。 然后我不必担心抽象推理或C#规范中的细节。

就在今天,我遇到了这样一个问题:如果我用相同的行填充相同类型的DataTable两次,会发生什么? 这一行的一个副本,还是两个? 即使我改变了它,它会覆盖第一行吗? 我想过问一个人,但我意识到我可以很容易地启动一个我已经使用DataSets的测试项目,编写一个小方法并测试它。

回答:

啊啊,但如果我告诉你,你会错过这一点。 :)关键是,在编程中你不必将这些东西留作假设,如果可以对它们进行合理的测试,你就不应该这样做。

所以我认为这是一个可怕的问题。 你不愿意雇用一个开发人员,他会尝试一下,然后知道会发生什么,而不是一个开发人员,他会尝试从他褪色的记忆中挖掘它,或者谁会问别人并接受一个答案可能是错的?

这是一个荒谬的问题 – 我可以在<60秒内使用Snippet Compiler回答它,如果我曾经在依赖于功能的代码库中工作 - 那么它很快就会被重构。

最好的答案是“这是一个愚蠢的设计,不要这样做,你不必解析语言规范来了解它将要做什么”。

如果我是受访者,我会高度评价你的极客琐事信誉,并且可能邀请你参加下一场极客琐事追求游戏。 但是,我不太确定我是否愿意和你一起工作。 如果这是你的目标,请务必提出要求。

  • 请注意,在非正式场合,像这样的极客琐事可以是有趣和有趣的。 但是,对于一个受访者来说,面试不过是有趣或非正式的 – 为什么进一步用一些微不足道的问题来鼓励他们,如果你认真对待,受访者不知道?

这给我一个棘手的问题。 如果你已经使用这种语言足够长的时间,你可能会遇到问题并知道答案; 但是多久就够了?

这也是你的背景可能对你不利的问题。 我知道在C ++中,B中的定义会隐藏A中的定义,但我不知道它是否在C#中的作用相同。 在现实生活中,我知道这是一个值得怀疑的领域,并试图查找它。 在一次采访中,我可能会尝试猜测,已被当场。 我可能会弄错。

只要你期望候选人告诉你他的思考过程,因为他描述了他认为应该发生的事情。 谁在乎有问题的实际代码的正确与错误 – 在现实世界中,候选人会找到这样的代码,发现它无法正常工作并使用调试器和写线调用的组合进行调试,所以如果你想要它是一个无用的问题知道(或猜测)正确答案的候选人。

但那些能够解释他们认为会发生什么的人,那是另一回事。 即使他们弄错了也雇用他们。

在实际工作情况下需要5秒才能找出问题所在。 编译,测试,哎呀。

我更担心的是,是否有人可以构建良好且可维护的代码。 问问题

  • 你会如何为此设计,编写简单的抽象设计,无需代码。
  • 这是一个对象设计。 客户来了,说他们想要这个。 制定新设计 – 或 – 讨论为什么要求无法满足实际客户需求的原因。

尝试下面给出的类似示例:

 class Program { class P {} class Q : P {} class A { public void Fee(Q q) { Console.WriteLine("A::Fee"); } } class B : A { public void Fee(P p) { Console.WriteLine("B::Fee"); } } static void Main(string[] args) { B b = new B(); /* which Fee is chosen? */ b.Fee(new Q()); Console.ReadKey(); } } 

如果可以隐式地转换参数以匹配任何这样的方法,编译器似乎更喜欢将“b.Fee()”调用链接到类型的可用方法而不是inheritance的方法(基类型的方法)。 即隐式转换参数优先于基类方法链接。

虽然老实说我觉得相反的更直观,因为对我来说,一个inheritance的方法和直接引入的方法一样好。

正如许多人已经说过的那样,当我采访某人时,我想知道候选人是否有能力进行交流,能够编写有意义的代码,并且可以被其他人轻易理解,可以维护的代码等等。 我个人不喜欢花时间参加提议的练习。 相反,我宁愿做一个练习,让候选人自己编写代码 – 甚至在常规文本编辑器中 – 并从那里开始基于代码审查的讨论,改进等等。 不需要编译代码:编译器最终会完成它的工作。 我知道很多人可能会对这种方法持不同意见,但到目前为止,我发现这是寻找优秀候选人的最佳方式。

有问题的代码将打印B::Foo