15个基本的c#面试问题 *

最好的c#开发人员和工程师可以回答的全部基本问题. 在我们社区的推动下,我们鼓励专家提交问题并提供反馈.

现在就聘请一名顶级c#开发人员
Toptal logo是顶级自由软件开发人员的专属网络吗, designers, finance experts, 产品经理, 和世界上的项目经理. 顶级公司雇佣Toptal自由职业者来完成他们最重要的项目.

面试问题

1.

下面这个短程序的输出是什么? 解释你的答案.

class Program {
  静态字符串位置;
  静态DateTime时间;
 
  静态void Main() {
    Console.WriteLine(location == null ? "位置为空": location);
    Console.WriteLine(time == null ? time is null:时间.ToString());
  }
}
View answer

输出将是:

位置为空
1/1/0001 12:00:00 AM

尽管这两个变量都未初始化, String 引用类型是and吗 DateTime 是一个值类型. 作为值类型,初始化的 DateTime 变量被设置为默认值午夜1/1/1(是的,那是a年.D.), not null.

2.

给定一个整型数组,编写一个c#方法计算所有偶数的总和.

View answer

当然,有很多方法可以做到这一点,但最直接的两种方法是:

TotalAllEvenNumbers(int[] intArray) {
  return intArray.Where(i => i % 2 == 0).Sum(i => (long)i);
}

or:

TotalAllEvenNumbers(int[] intArray) {
  return (from i in intArray where i % 2 == 0 select (long)i).Sum();
}

以下是在答案中寻找的关键内容:

  1. 候选人是否充分利用了c#语言结构,使单行解决方案成为可能(i.e., 而不是使用包含循环的冗长解决方案, 条件语句, 和蓄电池)?
  2. 候选人是否考虑过溢出的可能性. 例如,这样的实现 return intArray.Where(i => i % 2 == 0).Sum() (不管函数的返回类型是什么)可能是一个“显而易见的”单行解决方案, 但是这里溢出的概率很高. 而上述答案中使用的方法是转换为 long 并不能排除这种可能性, 这使得发生溢出异常的可能性极小. Note that, 如果候选人询问数组的预期大小及其成员的大小, 他或她显然在考虑这个溢出问题, 这是我们想要确定的.
3.

的比较 time and null in the if 下面的陈述是否有效? Why or why not?

静态DateTime时间;
/* ... */
If (time == null)
{
	/*做某事*/
}
View answer

有人可能会想,既然a DateTime 变量永远不能为空(它会自动初始化为1月1日), 0001), 编译器会报错 DateTime 变量与 null. However, 由于类型强制, 编译器允许这样做, 这可能会导致假头和拔毛虫.

具体来说, == 操作符将其操作数强制转换为不同的允许类型,以便在两边获得共同的类型, 然后它可以比较哪个. 这就是为什么像这样的东西会给你期望的结果(而不是失败或异常行为,因为操作数是不同的类型):

double x = 5.0;
int y = 5;
Console.WriteLine(x == y);  // outputs true

然而,这有时会导致意想不到的行为,就像比较 DateTime variable and null. 在这种情况下,两者 DateTime 变量和 null Literal可以强制转换为 Nullable. 因此,比较这两个值是合法的,即使结果会 always be false.

申请加入Toptal的发展网络

并享受可靠、稳定、远程 自由c#开发工作

申请成为自由职业者
4.

给定一个实例 circle 属于下列类别:

公共密封类Circle {
  专用双半径;
  
  public double Calculate(Func op) {
    返回op(半径);
  }
}

写代码计算圆的周长,无需修改 Circle class itself.

View answer

首选的答案是:

circle.Calculate(r => 2 * Math.PI * r);

因为我们无法进入 private radius 对象的字段, 我们告诉物体自己计算周长, 通过内联传递计算函数.

许多c#程序员回避(或不理解)函数值形参. 虽然在这种情况下,这个例子有点做作, 目的是看申请人是否理解如何制定一个电话到 Calculate 哪个匹配方法的定义.

Alternatively, 一个有效(虽然不太优雅)的解决方案是从对象中检索半径值本身,然后用结果执行计算:

半径=圆.Calculate(r => r);
var圆周= 2 *数学.PI * radius;

两种方法都可以. 我们在这里主要看的是应聘者是否熟悉, 并且知道如何调用, the Calculate method.

5.

下面程序的输出是什么? 解释你的答案.

class Program {
  私有静态字符串结果;
 
  静态void Main() {
    SaySomething();
    Console.WriteLine(结果);
  }
 
  static async Task SaySomething() {
    await Task.Delay(5);
    result = "Hello world .!";
    返回“东西”;
  }
}

同样,如果我们替换 await Task.Delay(5); with Thread.Sleep(5)? Why or why not?

View answer

问题第一部分的答案(1).e.,代码的版本 await Task.Delay(5);)是程序将只输出一个空行(not “Hello world!”). This is because result 何时仍未初始化 Console.WriteLine is called.

大多数面向过程和面向对象的程序员都希望函数从头到尾执行, or to a return 语句,然后返回调用函数. 这与c#不同 async functions. 它们只执行到第一次 await 语句,然后返回给调用者. 调用的函数 await (in this case Task.Delay)是异步执行的,并且 await 语句没有发出执行信号,直到 Task.Delay 完成(5毫秒). 但是,在此时间内,控制权已经返回给调用方,调用方执行 Console.WriteLine 语句在尚未初始化的字符串上执行.

Calling await Task.Delay(5) 让当前线程继续它正在做的事情, 如果完成了(等待完成), 将其返回到线程池. 这是async/await机制的主要好处. 它允许CLR在线程池中使用更少的线程来服务更多的请求.

异步编程已经变得越来越普遍, 随着对许多活动执行网络服务请求或数据库请求的设备的流行. c#有一些优秀的编程结构,极大地简化了异步方法的编程任务, 意识到这一点的程序员会写出更好的程序.

关于问题的第二部分,如果 await Task.Delay(5); 取而代之的是 Thread.Sleep(5),程序将输出 Hello world!. An async method without at least one await statement in it operates just like a synchronous method; that is, 它将从头到尾执行, 或者直到它遇到 return statement. Calling Thread.Sleep() 阻塞当前正在运行的线程,所以 Thread.Sleep(5) 的执行时间增加了5毫秒 SaySomething() method.

6.

下面程序的输出是什么? 解释你的答案.

委托无效打印机();

Main()
{
        List printers = new List();
        int i=0;
        for(; i < 10; i++)
        {
            printers.添加委托{控制台.WriteLine(i); });
        }

        Foreach(打印机中的var printer)
        {
            printer();
        }
}
View answer

这个程序将输出10这个数字10次.

原因如下:委托被添加到for循环中,并且“引用”(或者“指针”可能是更好的选择)到 i 是存储的,而不是值本身. 因此,在我们退出循环之后,变量 i 已设置为10,因此在调用每个委托时,传递给所有委托的值都是10.

7.

可以在一个数组中存储混合数据类型,如int, string, float, char?

View answer

Yes! 这样做是可能的,因为数组可以是类型 object 它不仅可以存储任何数据类型,还可以存储类的对象,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

名称空间ConsoleApplication8
{
    class Program
    {
        class Customer
        {
            public int ID { get; set; }
            public string Name { get; set; }
            公共覆盖字符串ToString()
            {
                return this.Name;
            }
        }
        静态void Main(string[] args)
        {
            Object [] array = new Object [3];
            Array [0] = 101;
            array[1] = " c# ";
            Customer c = new Customer();
            c.ID = 55;
            c.Name = "Manish";
            array[2] = c;
            Foreach(对象对象)
            {
                Console.WriteLine (obj);
            }
            Console.ReadLine();
        }
    }
}
8.

比较c#中的结构和类. 他们有什么共同点? 它们有什么不同??

View answer

c#中的类和结构确实有一些共同之处,即:

  • 是复合数据类型
  • 可以包含方法和事件吗
  • 可支持接口

但也有一些不同之处. 这里有一个比较:

Classes:

  • 支持继承
  • 是引用(指针)类型吗
  • 引用可以为空
  • 每个新实例都有内存开销

Structs:

  • 不支持继承
  • Are value types
  • 按值传递(如整数)
  • 不能有空引用(除非使用Nullable)
  • 每个新实例没有内存开销(除非“盒装”)
9.

下面程序的输出是什么?

公共类TestStatic
    {
        public static int TestValue;

        公共TestStatic ()
        {
            if (TestValue == 0)
            {
                TestValue = 5;
            }
        }
        静态TestStatic ()
        {
            if (TestValue == 0)
            {
                TestValue = 10;
            }
            
        }

        Print()
        {
            if (TestValue == 5)
            {
                TestValue = 6;                
            }
            Console.WriteLine("TestValue: " + TestValue);

        } 
    }

 public void Main(string[] args)
        {

            TestStatic = new TestStatic();
            t.Print();
        }
View answer

TestValue : 10

在创建类的任何实例之前调用类的静态构造函数. 的静态构造函数初始化 TestValue variable first.

10.
class ClassA
{
  public ClassA() {}

  public ClassA(int pValue) {}
}

在客户端:

class Program
{
  静态void Main(string[] args)
  {
    ClassA refA = new ClassA();
  }
}

Question:

有办法修改吗 ClassA 这样你就可以调用带参数的构造函数, 当Main方法被调用时, 类的任何其他新实例 ClassA?

View answer

The this 关键字用于调用其他构造函数,以初始化类对象. 实现如下:

class ClassA
{
  public ClassA(): this(10)
  { }

  public ClassA(int pValue)
  {  }
}
11.

下面的代码输出什么?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

小说名称空间
{
    class Program
    {
        静态void Main(string[] args)
        {
            try
            {
                Console.WriteLine(“Hello”);
            }
            抓住(ArgumentNullException)
            {
                Console.WriteLine(“A”);
            }
            抓住(异常)
            {
                Console.WriteLine (" B ");
            }
            finally
            {
                Console.WriteLine(“C”);
            }
            Console.ReadKey();
        }
    }
}
View answer
Hello
C
12.

描述依赖注入.

View answer

依赖注入是一种解除紧密链接类耦合的方法, 从而减少了类之间的直接依赖. 有几种不同的方式可以实现依赖注入:

  1. 构造函数依赖
  2. 属性的依赖
  3. 方法的依赖
13.

编写一个c#程序,接受千米为单位的距离, 换算成米, 然后显示结果.

View answer
using system;
class abc
{
    public static Void Main()
    {
        Int ndistance, nresult;
        Console.WriteLine("以公里为单位输入距离");
        Ndistance = convert.ToInt32(Console.ReadLine());
        Nresult = ndistance * 1000;
        Console.WriteLine("距离以米为单位:" + nresult);
        Console.ReadLine();
    }
}
14.

描述装箱和拆箱. 提供一个示例.

View answer

装箱是值类型到类型的隐式转换 object 或由值类型实现的任何接口类型. 装箱一个值类型会创建一个包含该值的对象实例,并将其存储在堆上.

Example:

int x = 101;
object o = x;  // boxing value of x into object o

o = 999;
x = (int)o;    // unboxing value of o into integer x
15.

给定一个至少包含一个的字串 $ symbol, e.g.:

“foo bar foo $ bar $ foo bar $”

问:如何除去除第一次出现外的所有 $ 从一个给定的字符串?

View answer

这个问题有两个部分:保留第一个出现的元素,替换所有其他的元素.

我们可以用正则表达式求解 String.Replace():

using System;
using System.Text.RegularExpressions;

类MainClass {
  Main (string[] args) {
    字符串s = "例如$你没有$网络$访问权限";
    Console.WriteLine("before: {0}", s);

    GroupCollection semiconductors = Regex.匹配的 , @"([^$]*\$)(.*)").Groups;
    字符串答案= [1].Value +二分之一[2].Value.取代 ("$", "");
    
    Console.WriteLine("after: {0}", answer);
    //例如$你没有网络访问权限
  }
}

Explanation:

  • ([^$]*\$)-组1捕获任意数量的非-$ 字符,加上一个 $ 字符(用。转义 \)
  • (.*)-第二组(贪婪地)捕获其他一切

的第一次出现 $ preserved in halves[1].Value,我们可以简单地使用 String.Replace() on halves[2].Value 消除所有 $ 在字符串的其余部分中找到的字符,不需要第二个正则表达式.

面试不仅仅是棘手的技术问题, 所以这些只是作为一个指南. 并不是每一个值得雇佣的“A”候选人都能回答所有的问题, 回答所有问题也不能保证成为A级考生. 一天结束的时候, 招聘仍然是一门艺术,一门科学,需要大量的工作.

Why Toptal

厌倦了面试候选人? 不知道该问什么才能让你得到一份好工作?

让Toptal为你找到最合适的人.

现在就聘请一名顶级c#开发人员

我们的c#开发者专属网络

想找一份c#开发人员的工作?

让Toptal为你找到合适的工作.

申请成为c#开发人员

工作机会从我们的网络

提出面试问题

提交的问题和答案将被审查和编辑, 并可能会或可能不会选择张贴, 由Toptal全权决定, LLC.

*所有字段均为必填项

寻找c#开发人员?

Looking for C# Developers? 查看Toptal的c#开发人员.

Rory Woods

自由c#开发人员

United StatesToptal的自由c#开发人员 Since June 5, 2014

Rory是一名软件顾问,提供满足企业需求的解决方案. 他带来了技术技能和经验,不仅指导团队如何构建,还指导团队构建什么. 他在微软web堆栈方面拥有丰富的经验,包括ASP.NET MVC、Web API、SQL Server和Azure.

Show More

Rizwan Rizvi

自由c#开发人员

United StatesToptal的自由c#开发人员 Since June 13, 2018

里兹万以通过清晰的思维克服复杂的挑战而闻名, 创新的方法, 加强组织不同部门之间的沟通. 在他的职业生涯中, 他优化了多样化和分散的IT专业人员团队的工作,并在具有挑战性的环境中始终如一地交付了有利可图的项目.

Show More

Dan Napierski

自由c#开发人员

United StatesToptal的自由c#开发人员 Since April 28, 2016

Dan是一名专注于区块链技术应用的软件架构师和技术专家. 他拥有多年的专业咨询服务经验,为从初创公司到跨国公司的客户提供服务. 他擅长将严格的测试和防弹代码引入棘手的工程挑战. 他在人工智能的许多方面都有深厚的专业知识, blockchain, 机器学习, and automation.

Show More

Toptal连接 Top 3% 世界各地的自由职业人才.

加入Toptal社区.

Learn more