美文网首页
11道必会的C#面试题

11道必会的C#面试题

作者: 高效工具库 | 来源:发表于2018-08-29 17:36 被阅读0次


    更多资源 or 免费科学上网工具
    请关注公众号:高效工具库(ID: gaoxiaogongjuku )

    写一个方法,求int数组的和

    参考答案

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

    关键点

    • 候选人是否利用C#语言特点,简化代码使解决方案更简洁(而不是使用包含循环,条件语句和累加器的更长的解决方案)
    • 候选人是否考虑到了溢出。比如:使用return intArray.Where(i => i % 2 == 0).Sum() 虽然只有一行,也很简单,但是溢出的可能性很高。而在上诉答案中溢出的可能性小了很多,如果候选人询问数组的大小的话,那么说明他正在考虑溢出的问题,这是非常好的

    以下程序输出的内容是什么,并解释原因

    class Program 
    {
      static String location;
      static DateTime time;
     
      static void Main() 
      {
        Console.WriteLine(location == null ? "location is null" : location);
        Console.WriteLine(time == null ? "time is null" : time.ToString());
      }
    }
    

    参考答案
    location is null
    1/1/0001 12:00:00 AM
    解释如下:虽然两个变量都未初始化,但是String引用类型 ,而 DateTime值类型,其默认值为 1/1/1 而非 null

    if语句中的time和null比较是否有效? 为什么?

    static DateTime time;
    /* ... */
    if (time == null)
    {
        /* do something */
    }
    

    参考答案
    有人可能会认为,由于DateTime变量永远不能为空(它自动初始化为0001年1月1日),因此当DateTime变量与null进行比较时,编译器会报错。但是,由于类型转换,编译器确实允许它,这可能会导致一些让你头疼的问题。

    具体来说,==运算符会将等号两边的对象都转换成相同的类型,然后可以进行比较。这就是为什么像这样的写法会给你你期望的结果(而不是因为操作数是不同的类型而导致失败或表现异常):

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

    但是,这有时会导致意外行为,比如DateTime变量和null的比较。在这种情况下,DateTime变量和null文字都可以强制转换为Nullable <DateTime>。因此,比较这两个值是合法的,即使结果总是false。

    不修改 Circle 类的定义,计算圆的周长

    Circle 类的定义如下:

    public sealed class Circle 
    {
      // 半径
      private double radius;
      
      public double Calculate(Func<double, double> op)
      {
        return op(radius);
      }
    }
    

    给你一个 Circle 的实例 circle,计算它的周长
    参考答案

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

    由于我们无法访问对象的私有半径字段,因此我们告诉对象本身计算周长,方法是将计算函数传递给它。

    许多C#程序员回避(或不理解)函数值参数。 虽然在这种情况下这个例子有点人为,但目的是看看申请人是否理解如何制定一个与Method的定义匹配的Calculate调用。

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

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

    无论哪种方式都有效。 我们主要想看到候选人熟悉并理解如何调用Calculate方法。

    兵哥注: 我感觉添加一个静态扩展方法会更好

     public static class CircleExtention
        {
            public static double GetCircumference(this Circle circle)
            {
                return circle.Calculate(r => Math.PI * r * 2);
            }
        }
    

    【async/await】以下程序会输出什么?为什么。

        class Program
        {
            private static int result ;
    
            static void Main()
            {
                var task = SaySomething();
                Console.WriteLine(result);         
            }
    
            static async Task<int> SaySomething()
            {
                Console.WriteLine(1);
                await Task.Delay(50);
                Console.WriteLine(2);
                result = 3;
                return 4;
            }         
        }
    

    参考答案
    输出为
    1
    0
    tip 由于主线程没有等待子线程结束,所以子线程在主线程结束后立即被释放 所以 Console.WriteLine(2); 未被执行
    兵哥注
    对于 async 方法SaySomething被主线程调用时,主线程会一直执行async的方法,直到遇到await , 主线程将会从线程池中获取一个空闲的子线程,并把await 的Task.Delay方法 以及SaySomething中位于 await 后的所有代码交给子线程处理

    可使用一下代码验证

        class Program
        {
            private static int result;
    
            static void Main()
            {
                Console.WriteLine($"Main Thread:{Thread.CurrentThread.ManagedThreadId}");
                var task = SaySomething();
                Console.WriteLine(result);
                Console.WriteLine(task.Result);
            }
    
            static async Task<int> SaySomething()
            {
                Console.WriteLine($"SaySomething Thread before await:{Thread.CurrentThread.ManagedThreadId}");
                Console.WriteLine(1);
                await Task.Delay(50);
                Console.WriteLine($"SaySomething Thread after await:{Thread.CurrentThread.ManagedThreadId}");
                Console.WriteLine(2);
                result = 3;
                return 4;
            }
        }
    

    【delegate】以下程序会输出什么?为什么。

        class Program
        {
            delegate void Printer();
    
            static void Main()
            {
                List<Printer> printers = new List<Printer>();
                int i = 0;
                for (; i < 10; i++)
                {
                    printers.Add(delegate { Console.WriteLine(i); });
                }
    
                foreach (var printer in printers)
                {
                    printer();
                }
            }
        }
    

    参考答案
    将会输出10个10
    因为所有的委托中的变量i都是指向同一块内存地址
    兵哥注
    对比代码如下

        class Program
        {
            delegate void Printer();
    
            static void Main()
            {
                List<Printer> printers = new List<Printer>();
                int i = 0;
                for (; i < 10; i++)
                {
                    var j = i;
                    printers.Add(delegate { Console.WriteLine(j); });
                }
    
                foreach (var printer in printers)
                {
                    printer();
                }
            }
        }
    

    是否可以在一个数组中储存各种不同类型的对象?

    参考答案 可以,因为C#中所有的对象都继承自Object,所以可以使用object[] array = new object[3]; 来存储

    比较C#中的 class 和 struct,它们有什么异同?

    参考答案

    • 相同点
      1. 都是混合数据类型
      2. 都可以包含方法和事件
      3. 都可以继承接口
    • 不同点
    特点 class struct
    是否支持继承 支持 不支持
    引用类型/值类型 引用类型 值类型
    值是否可为null
    新的实例是否会消耗没存 否(除非被装箱)

    【执行顺序】以下程序会输出什么

    public class TestStatic
    {
     public static int TestValue = InitTestValue();
    
     private static int InitTestValue() 
     {
         if (TestValue == 0)
         {
             TestValue = 20;
         }
     
         return 30;
     }
    
     public TestStatic()
     {
         if (TestValue == 0)
         {
             TestValue = 5;
         }
     }
     static TestStatic()
     {
         if (TestValue == 0)
         {
             TestValue = 10;
         }
     }
    
     public void Print()
     {
         if (TestValue == 5)
         {
             TestValue = 6;
         }
         Console.WriteLine("TestValue : " + TestValue);
    
     }
    }
    
    public static void Main(string[] args)
    {
    
     TestStatic t = new TestStatic();
     t.Print();
    }
    

    参考答案 TestValue:30
    执行顺序:静态变量赋值表达式=>静态构造函数=》构造函数

    【exception】以下程序会输出什么

    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Hello");
            throw new ArgumentNullException();
        }
        catch (ArgumentNullException)
        {
            Console.WriteLine("A");
        }
        catch (Exception)
        {
            Console.WriteLine("B");
        }
        finally
        {
            Console.WriteLine("C");
        }
        Console.ReadKey();
    }
    

    参考答案
    Hello
    A
    C

    什么是依赖注入(Dependency injection)

    依赖注入是一种解除类之间直接依赖关系的方法,有以下几种注入方式:构造函数注入,属性注入,方法注入
    兵哥注 可以看看微软的依赖注入库 Unity
    <package id="Unity" version="5.2.0" targetFramework="net452" />
    <package id="Unity.Mvc5" version="1.3.0" targetFramework="net452" />

    更多资源 or 免费科学上网工具

    请关注公众号:高效工具库(ID: gaoxiaogongjuku )

    相关文章

      网友评论

          本文标题:11道必会的C#面试题

          本文链接:https://www.haomeiwen.com/subject/wdpkwftx.html