【學習筆記】C#面試題(一)

1、給定一個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();
}

當然,你還需要注意以下關鍵:

  1. 你是否利用 C#語言特性 一行就解決問題。(即,不是使用包含循環,條件語句和累加器的更長篇幅的解決方案)
  2. 你是否考慮過溢出的可能性。例如,諸如return intArray.Where(i => i % 2 == 0).Sum()(與函數的返回類型無關)

這可能一個很”明顯”的單行,但這樣溢出的可能性很高。雖然上面的答案中使用的轉換爲long的方法並沒有消除這種可能性,但是它使得發生溢出異常的可能性非常小。但請注意,如果你寫答案的時候詢問數組的預期大小及其成員的大小,則顯然你在做這道題目的時候在考慮此溢出問題,這很棒。

2、下面的代碼的輸出是什麼?解釋你的答案。

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 是值類型。作爲值類型,單位化DateTime變量設置爲默認值 公元1年晚上12點,而不是 null

3、下面語句中 time 和null 的比較是有效還是無效的?

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

有人可能會認爲,由於變量永遠不可能爲null (它被自動初始化爲1月1日的值),所以編譯器在比較某個變量時就會報錯。具體來說,操作符將其操作數強制轉換爲不同的允許類型,以便在兩邊都得到一個通用類型,然後可以對其進行比較。這就是爲什麼像這樣的東西會給你期望的結果(而不是失敗或意外的行爲,因爲操作數是不同的類型):

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

然而,這有時會導致意外的行爲,例如DateTime變量和null的比較。在這種情況下,DateTime變量和null文字都可以轉換爲可空的。因此,比較這兩個值是合法的,即使結果總是假的。

4、給定circle以下類的實例:

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

簡編寫代碼以計算圓的周長,而無需修改Circle類本身。
首選的答案如下:

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

由於我們不能訪問對象的私有半徑字段,所以我們通過內聯傳遞計算函數,讓對象本身計算周長。

許多c#程序員迴避(或不理解)函數值參數。雖然在這種情況下,這個例子有點做作,但其目的是看看申請人是否瞭解如何制定一個調用來計算哪個與方法的定義相匹配。

另外,一個有效的(雖然不那麼優雅的)解決方案是從對象中檢索半徑值本身,然後執行計算結果:

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

無論哪種方式。我們在這裏主要尋找的是面試者是否熟悉並理解如何調用Calculate方法。

5、下面程序的輸出是什麼?解釋你的答案。

class Program {
  private static string result;
 
  static void Main() {
    SaySomething();
    Console.WriteLine(result);
  }
 
  static async Task<string> SaySomething() {
    await Task.Delay(5);
    result = "Hello world!";
    return “Something”;
  }
 

下面
此外,如果我們替換wait task,答案會改變嗎? 比如 thread . sleep (5) ? 爲什麼?的簡短

程序的輸出是什麼?解釋你的答案。序的輸出是什麼?解釋你的答案。

回答:

問題第一部分(即帶有的代碼版本await Task.Delay(5);)的答案是該程序將僅輸出一個空行(而不是 “ Hello world!”)。這是因爲調用result時仍將未初始化Console.WriteLine。

大多數程序和麪向對象的程序員都希望函數return在返回調用函數之前從頭到尾執行,或者從語句執行。C#async函數不是這種情況。它們只執行到第一個await語句,然後返回到調用方。由await(在此例中爲Task.Delay)調用的函數是異步執行的,並且該await語句之後的行直到Task.Delay完成(在5毫秒內)之前都不會發出信號。但是,在這段時間內,控制權已經返回給調用者,該調用者Console.WriteLine對尚未初始化的字符串執行該語句。

調用await Task.Delay(5) 可讓當前線程繼續其正在執行的操作,如果已完成(等待任何等待),則將其返回到線程池。這是異步/等待機制的主要好處。它允許CLR使用線程池中的更少線程來服務更多請求。

異步編程已經變得越來越普遍,因爲執行許多活動的網絡服務請求或數據庫請求的設備越來越普遍。C#具有一些出色的編程結構,可以極大地簡化異步方法的編程任務,並且意識到它們的程序員將產生更好的程序。

關於問題的第二部分,如果將await Task.Delay(5);其替換爲Thread.Sleep(5),則程序將輸出Hello world!。一種沒有至少一個語句的async方法,其操作就像同步方法一樣。也就是說,它將從頭到尾執行,或者直到遇到一條語句爲止。調用只是阻塞了當前正在運行的線程,因此調用僅將方法的執行時間增加了5毫秒。awaitreturnThread.Sleep()Thread.Sleep(5)SaySomething()

6、下面的程序輸出是什麼?解釋你的答案。

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輸出十次。

原因如下: 委託被添加到 for循環中l了,而 “引用” (或者“指針”)被存儲到i中,而不是值本身。因此,在我們退出循環之後,變量i被設置爲10,所以到調用每個委託時,傳遞給它們的值都是10。

7、是否可以將混合數據類型(例如int,string,float,char)全部存儲在一個數組中?

是! 之所以可以這樣做,是因爲數組的類型object不僅可以存儲任何數據類型,還可以存儲類的對象,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication8
{
    class Program
    {
        class Customer
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public override string ToString()
            {
                return this.Name;
            }
        }
        static 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 (object obj in array)
            {
                Console.WriteLine(obj);
            }
            Console.ReadLine();
        }
    }
}
 

8、比較C#中的結構和類。他們有什麼共同點?它們有何不同?

C#中的類和結構確實有一些共同點,即:

他們都是

是複合數據類型

可以包含方法和事件

可以支持接口

但是有許多差異。比較一下:

類:

支持繼承

是引用(指針)類型

引用可以爲空

每個新實例都有內存開銷

結構:

不支持繼承

是值類型

按值傳遞(如整數)

不能有空引用(除非使用了Nullable)

每個新實例沒有內存開銷(除非“裝箱”)

9、這裏有一個包含一個或多個$符號的字串,例如:

"foo bar foo $ bar $ foo bar $ "

問題:如何$從給定的字符串中刪除第二和第三次出現的?
答案:

使用如下正則表達式:

string s = "like for example $  you don't have $  network $  access";
Regex rgx = new Regex("\\$\\s+");
s = Regex.Replace(s, @"(\$\s+.*?)\$\s+", "$1$$");
Console.WriteLine("string is: {0}",s);
 

說明:

  • ($\s+.*?)-第1組,捕獲一個文字$,一個或多個空格字符,然後捕獲除換行符以外的任意數量的字符,並儘可能少地捕獲到下一個最接近的匹配項
  • $\s+—單個$符號和一個或多個空格字符
  • $1引用組1的值,它只是將其插入被替換的字符串中,$$代表替換模式中的$符號。

10、下面的程序輸出是什麼?

public class TestStatic
    {
        public static int TestValue;
        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 void Main(string[] args)
        {
            TestStatic t = new TestStatic();
            t.Print();
        }
 
TestValue : 10

在創建該類的任何實例之前,將調用該類的靜態構造函數。此處調用的靜態構造函數TestValue首先將變量初始化。

11、有沒有一種方法可以修改ClassA、以便您可以在調用Main方法時使用參數調用構造函數,而無需創建任何其他新實例ClassA?

class ClassA
{
  public ClassA() { }
  public ClassA(int pValue) {  }
}
 

啓動類

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

回答:

所述this關鍵字被用於調用其他構造,初始化該類對象。下面是實現:

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

12、以下代碼輸出什麼?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace main1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Hello");
            }
            catch (ArgumentNullException)
            {
                Console.WriteLine("A");
            }
            catch (Exception)
            {
                Console.WriteLine("B");
            }
            finally
            {
                Console.WriteLine("C");
            }
            Console.ReadKey();
        }
    }
}
 

答案:

Hello
C
 

13、描述依賴注入。

依賴注入是一種使緊密鏈接的類分離的方式,從而減少了類之間的直接依賴。有多種方法可以實現依賴項注入:

  1. 構造函數依賴
  2. 屬性依賴
  3. 方法依賴

14、編寫一個C#程序,該程序接受以千米爲單位的距離,將其轉換爲米,然後顯示結果。

using system;
class abc
{
    public static Void Main()
    
    {
      
            int ndistance, nresult;
            
        Console.WriteLine("Enter the distance in kilometers");
        
        ndistance = convert.ToInt32(Console.ReadLine());
        
        nresult = ndistance * 1000;
          
        Console.WriteLine("Distance in meters: " + nresult);
        
        Console.ReadLine();
        
    }
    
}
 

15、描述裝箱和拆箱。並寫一個例子。

裝箱是將值類型隱式轉換爲該類型object或該值類型實現的任何接口類型。將值類型裝箱會創建一個包含該值的對象實例,並將其存儲在堆中。

例:

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章