天天看點

2019-11-19-C#-進階面試題

title author date CreateTime categories
C# 進階面試題 lindexi 2019-11-19 08:40:50 +0800 2018-11-12 11:18:2 +0800 C#

很少會有人可以答對,如果你遇到一個來面試的人實在嚣張,就可以用本文的題去打擊

本文内容就看着玩,請不要在嚴肅的面試中問題這樣的題目

如果面試到一個人可以回答出下面的題目也不能證明他的技術很強,隻能說明他了解很多C#相關,或者他看過我的部落格

循環下面的代碼

請在下面的代碼的注釋處填寫代碼,讓函數 Foo 裡面的代碼輸出

static void Main(string[] args)
        {
            // 請在此處寫代碼,調用 Foo 函數内的輸出代碼
        }

        private static void Foo()
        {
            try
            {
                while (true)
                {
                }
            }
            finally
            {
                Console.WriteLine("嘗試調用 Foo 函數執行這一句代碼");
            }
        }      

參考答案

使用一個線程調用的方式,調用之後結束線程,此時就會輸出

static void Main(string[] args)
        {
            // 請在此處寫代碼,調用 Foo 函數内的輸出代碼

            var thread = new Thread(Foo);
            thread.Start();
            Task.Delay(100).Wait();
            thread.Abort();// 這時就會結束循環

            Console.Read();
        }      

注意,在 dotnet core 不支援 Abort 方法

從空轉換

請寫出 IFoo 和 Foo 的實作,讓下面的代碼不會抛出空異常

static void Main(string[] args)
        {
            Foo foo = (IFoo) null;
            foo.Name = "lindexi";

            Console.Read();
        }      

參考答案

class IFoo
    {

    }

    class Foo
    {
        public string Name { get; set; }

        public static implicit operator Foo(IFoo foo)
        {
            return new Foo();
        }
    }      

等待不存在的類

請添加新的類的代碼讓下面的代碼編譯通過

class Program
    {
        static async Task Main(string[] args)
        {
            Foo foo = await (object) null;
            foo.Name = "lindexi";

            Console.Read();
        }
    }

    public class Foo
    {
        public string Name { get; set; }
    }      

參考答案

public class HeabdsdnbKevx : INotifyCompletion
    {
        public bool IsCompleted { get; }

        public Foo GetResult()
        {
            return new Foo();
        }

        /// <inheritdoc />
        public void OnCompleted(Action continuation)
        {
        }
    }

    public static class RelelnisSou 
    {
        public static HeabdsdnbKevx GetAwaiter(this object obj)
        {
            return new HeabdsdnbKevx();
        }
    }      

再進階一點,寫出下面的代碼

static async Task Main(string[] args)
        {
            await await await await await await await await await await await await
                await await await await await await await "林德熙是逗比";
        }      

其實很簡單,也就是将 GetResult 修改一下,在上面的代碼修改

public string GetResult()
        {
            return "林德熙是逗比";
        }      

因為傳回值是 string 是以又可以繼續等待

如何不執行 finally 裡面的代碼

這裡有一個代碼,需要讓 finally 裡面的代碼不執行,現在你隻能寫 Foo 方法,同時這個方法不能運作無限長時間

try
            {
                Foo();
            }
            finally
            {
                Console.WriteLine("不要讓這個代碼運作");
            }       

參考答案

因為不能讓 Foo 運作無限長,就不能使用無限循環的方法,可以使用的方法有 Environment.FailFast 或 Environment.Exit 退出

private static void Foo()
{
    Environment.Exit(0);
}      

或者進行堆棧溢出,如下面代碼

private static void Foo()
        {
            Foo();
        }      

或者 少珺 小夥伴的不安全代碼申請

private static void Foo()
        {
            unsafe
            {
                var n = stackalloc int[int.MaxValue];
            }
        }      

或者幹掉自己程序

private static void Foo()
        {
           Process.GetCurrentProcess().Kill();
        }      

但是申請大記憶體和退出目前線程方法都會讓 finally 執行

private static void Foo()
        {
            var n = new int[int.MaxValue];
        }
        // 雖然提示記憶體不夠,但是finally依然可以運作      

退出目前線程抛出的是線程中斷異常,和其他異常一樣都能執行 finally 代碼

private static void Foo()
        {
            Thread.CurrentThread.Abort();
        }      

注意,在 dotnet core 不支援 Abort 方法

另外,如果進入 try 是不能使用 goto 跳出但不執行 finally 代碼

如果是在 VisualStudio 調試,在 Foo 執行完之後,在 VS 裡把調試箭頭拖到 finally 的後面

請問下面代碼輸出多少

請問下面的代碼的 n 的值是多少?

class Foo
        {
            public int N { get; } = 1;
        }

            Foo foo = null;
            var n = 2 + foo?.N ?? 1;

            Console.WriteLine(n);      

參考答案

1

可能有小夥伴認為在

2 + foo?.N

這時如果 foo 為空就應該傳回

??

後面的值,但是這是不對的上面的代碼是和下面的代碼差不多等同的

if (foo == null)
            {
                n = 1;
            }
            else
            {
                n = 2 + foo.N;
            }      

而不是和下面的代碼等價的

if (foo == null)
            {
                n = 2 + 1;
            }
            else
            {
                n = 2 + foo.N;
            }      

在表達裡面隻有

?

的值為空,那麼就不會執行

等等,為什麼上面的代碼說的是差不多等同而不是等價,因為嘗試運作下面代碼,會看到 Hi 輸出,多謝 九鼎 指出

using System;
class Test
{
    class Foo
    {
        public int N
        {
            get
            {
                Console.WriteLine("Hi.");
                return 1;
            }
        }
    }

    static void Main()
    {
        Foo foo = null;
        Foo foo2 = new Foo();
        var n = 2 + foo?.N + foo2.N ?? 1;
        Console.WriteLine(n);
    }
}      

上面代碼中,第一個

foo?.N

會進行判斷,因為 foo 不存在,是以整個表達式沒有執行,但是表達式内的邏輯依然執行

模式比對

請問下面代碼輸出什麼?

class B
    {
        public static int operator &(B left, B right) => 1;
        public static int operator >(B left, B right) => 2;
        public static int operator <(B left, B right) => 3;

        public static int operator &(bool left, B right) => 5;
        public static int operator >(bool left, B right) => 6;
        public static int operator <(bool left, B right) => 7;
    }

        private static B B { get; }

        static void Main(string[] args)
        {
            object a = null;
            B c = null;
            Console.WriteLine(a is B b & c);
            Console.WriteLine(a is B b1 > c);
            Console.WriteLine(a is B b2 < c);

            a = new B();

            Console.WriteLine(a is B b5 & c);
            Console.WriteLine(a is B b6 > c);
            Console.WriteLine(a is B b7 < c);

        }      

也許這是全部題目裡面最簡單的一道題

請看 C# 比對可空變量

其實這裡的

a is B

用的

B

class

不是定義的屬性,對

a is B b5

傳回的是

bool

是以将會是

bool

B

之間的運算