Những câu hỏi phỏng vấn C#/.Net (junior + middle)
28. Việc xử lý exception được thực hiện như thế nào trong C#?
Xử lý exception được thực hiện bằng cách sử dụng bốn từ khóa trong C#:
- try – Chứa một khối mã mà exception sẽ được kiểm tra.
- catch – Nó là một chương trình bắt một exception với sự trợ giúp của trình xử lý exception.
- finally – Nó là một khối mã được viết để thực thi bất kể exception có bị bắt hay không.
- throw – Thảy ra một exception khi sự cố xảy ra.
29. Boxing và Unboxing là gì?
Boxing và Unboxing đều được sử dụng để chuyển đổi kiểu nhưng có một số khác biệt:
- Boxing – Boxing là quá trình chuyển đổi kiểu dữ liệu kiểu giá trị sang đối tượng hoặc sang bất kỳ kiểu dữ liệu interface nào được thực hiện bởi kiểu giá trị này. Khi CLR đóng gói một giá trị có nghĩa là khi CLR chuyển đổi một kiểu giá trị thành kiểu Object, nó sẽ bao bọc giá trị bên trong một System.Object và lưu trữ nó trên vùng heap trong miền ứng dụng.
- Unboxing – Unboxing cũng là một quá trình được sử dụng để trích xuất loại giá trị từ đối tượng hoặc bất kỳ loại interface nào được triển khai. Boxing có thể được thực hiện ngầm, nhưng Unboxing phải rõ ràng bằng mã.
Khái niệm boxing và unboxing nhấn mạnh quan điểm thống nhất của C # về hệ thống kiểu trong đó một giá trị của bất kỳ kiểu nào cũng có thể được coi như một đối tượng.
30. Bạn có thể truyền tham số cho một phương thức bằng bao nhiêu cách?
Có ba cách mà các tham số có thể được truyền cho một phương thức:
- Value parameters (tham số giá trị) – Phương thức này sao chép giá trị thực của một đối số vào tham số chính thức của hàm. Trong trường hợp này, các thay đổi được thực hiện đối với tham số bên trong hàm không ảnh hưởng đến đối số.
- Reference parameters (tham số tham chiếu) – Phương thức này sao chép tham chiếu đến vị trí bộ nhớ của một đối số vào tham số chính thức. Điều này có nghĩa là các thay đổi được thực hiện đối với tham số sẽ ảnh hưởng đến đối số.
- Output parameters (tham số đầu ra) – Phương thức này giúp trả về nhiều hơn một giá trị.
31. Partial class là gì?
Một partial class được sử dụng để phân chia phần định nghĩa của một lớp thành hai hoặc nhiều lớp trong cùng một hoặc nhiều tệp mã nguồn. Bạn có thể tạo định nghĩa lớp trong nhiều tệp nhưng nó sẽ được biên dịch thành một lớp tại runtime và cũng như khi bạn tạo một instance của lớp này để bạn có thể truy cập tất cả các phương thức từ tất cả tệp nguồn với cùng một đối tượng.
Các partial class chỉ có thể được tạo trong cùng một namespace, nó không được phép được tạo trong các namespace khác nhau.
32. This có thể được sử dụng trong một phương thức Static không?
Chúng ta không thể sử dụng this trong phương thức static vì từ khóa this trả về một tham chiếu đến instance hiện tại của lớp chứa nó.
Các phương thức static (hoặc bất kỳ thành viên static nào) không thuộc về một instance cụ thể. Chúng tồn tại mà không cần tạo một instance của lớp và được gọi bằng tên của một lớp mà không phải theo instance, vì vậy chúng ta không thể sử dụng từ khóa này trong phần thân của phương thức Static, nhưng trong trường hợp phương thức mở rộng, chúng ta có thể sử dụng nó làm tham số hàm.
33. Generics trong C # là gì?
Generics cho phép bạn trì hoãn việc đặc tả kiểu dữ liệu của các phần tử lập trình trong một lớp hoặc một phương thức, cho đến khi nó thực sự được sử dụng trong chương trình.
class DataStore<T>
{
public T Data { get; set; }
}
DataStore<string> store = new DataStore<string>();
34. Reference Type trong C # là gì?
Các reference type không chứa dữ liệu thực tế được lưu trữ trong một biến, mà chúng chứa một tham chiếu đến các biến.
Nói cách khác, chúng đề cập đến một vị trí bộ nhớ. Sử dụng nhiều biến, các reference type có thể tham chiếu đến một vị trí bộ nhớ. Nếu dữ liệu trong vị trí bộ nhớ bị thay đổi bởi một trong các biến, thì biến kia sẽ tự động phản ánh sự thay đổi này theo giá trị. Ví dụ về các reference type có sẵn là: object, dynamic, và string.
35. LINQ trong C # là gì?
LINQ là viết tắt của Language Integrated Query. LINQ có khả năng truy vấn tuyệt vời trên bất kỳ nguồn dữ liệu nào. Nguồn dữ liệu có thể là tập hợp các đối tượng, cơ sở dữ liệu hoặc tệp XML. Chúng ta có thể dễ dàng truy xuất dữ liệu từ bất kỳ đối tượng nào thực hiện interface IEnumerable <T>.
36. enum trong C # là gì?
Một enum là một kiểu giá trị với một tập hợp các hằng số được đặt tên có liên quan thường được gọi là danh sách liệt kê (enumerator list). Từ khóa enum được sử dụng để khai báo một kiểu liệt kê. Nó là một kiểu dữ liệu primitive, do người dùng định nghĩa. Một enum được sử dụng để tạo các hằng số trong .NET framework. Tất cả các thành viên của enum đều thuộc kiểu enum. Chúng phải là một giá trị số (numeric value) cho mỗi kiểu enum.
Vài nét về enum:
- enum là kiểu dữ liệu liệt kê trong C#.
- enum là hằng số strongly typed. Chúng là strongly typed, tức là một enum của một loại không được gán ngầm cho một enum của một loại khác mặc dù giá trị cơ bản của 2 loại đó là như nhau.
- enum (viết tắt của enumerations) làm cho mã của bạn dễ đọc và dễ hiểu hơn nhiều.
- Giá trị enum được cố định. Enum có thể được hiển thị dưới dạng một chuỗi và được xử lý dưới dạng số nguyên.
- Kiểu mặc định là int và các kiểu được chấp nhận là byte, sbyte, short, ushort, uint, long và ulong.
- Mọi kiểu enum đều tự động lấy từ System.Enum và do đó chúng ta có thể sử dụng các phương thức System.Enum trên enum.
- enum là các loại giá trị và được tạo trên stack chứ không phải trên heap.
37. Tại sao lại sử dụng khối finally trong C#?
Khối finally sẽ được thực thi bất kể có exception hay không. Do đó khi thực thi mã trong khối try khi exception xảy ra, quyền điều khiển được trả về khối catch và khối finally sẽ được thực thi. Vì vậy, việc đóng kết nối với cơ sở dữ liệu / giải phóng các trình xử lý tệp có thể được để trong khối finally.
38. Các kiểu Nullable trong C # là gì?
Một kiểu được cho là nullable nếu nó có thể được gán một giá trị hoặc có thể được gán null, có nghĩa là kiểu không có giá trị nào. Theo mặc định, tất cả các kiểu tham chiếu, chẳng hạn như String, là nullable, nhưng tất cả các kiểu giá trị, chẳng hạn như Int32, thì không.
Ví dụ: bạn có thể lưu trữ bất kỳ giá trị nào từ -2,147,483,648 đến 2,147,483,647 hoặc null trong một biến Nullable<Int32>. Tương tự, bạn có thể gán true, false hoặc null trong một biến Nullable<bool>.
39. Sự khác biệt giữa Struct và Class trong C # là gì?
Cả Class và Struct đều là kiểu dữ liệu do người dùng xác định nhưng có một số khác biệt chính:
Struct
- Struct là kiểu giá trị trong C# và nó kế thừa từ System.Value.
- Struct thường được sử dụng cho lượng dữ liệu nhỏ hơn.
- Struct không thể được kế thừa sang kiểu khác.
- Một Struct không thể là abstract.
Class
- Class là kiểu tham chiếu trong C# và nó kế thừa từ System.Object.
- Các Class thường được sử dụng cho một lượng lớn dữ liệu.
- Class có thể được kế thừa sang Class khác.
- Một Classcó thể là kiểu abstract.
- Chúng ta có thể tạo một phương thức khởi tạo mặc định.
40. Kể tên các loại lớp khác nhau trong C# ?
Các loại lớp khác nhau trong C# là:
- Partial class – Cho phép các thành viên của nó được chia ra hoặc chia sẻ với nhiều tệp .cs. Nó được biểu thị bằng từ khóa Partial.
- Sealed class – Là lớp không thể được kế thừa. Để truy cập các thành viên của một sealed class, chúng ta cần tạo đối tượng của lớp đó. Nó được biểu thị bằng từ khóa Sealed.
- Abstract class – Là lớp mà đối tượng của nó không thể được khởi tạo. Lớp chỉ có thể được kế thừa. Nó phải chứa ít nhất một phương thức. Nó được biểu thị bằng từ khóa abstract.
- Static class – Là lớp không cho phép kế thừa. Các thành viên của lớp cũng là static. Nó được biểu thị bằng từ khóa static. Từ khóa này yêu cầu trình biên dịch kiểm tra bất kỳ trường hợp ngẫu nhiên nào của static class.
41. Sự khác biệt giữa string và StringBuilder trong C # là gì?
string
- string là một đối tượng không thay đổi giữ giá trị chuỗi.
- string có hiệu suất chậm vì nó tạo một phiên bản mới để ghi đè hoặc thay đổi giá trị trước đó.
- string thuộc về namespace System.
StringBuilder
- StringBuilder là một đối tượng có thể thay đổi.
- Hiệu suất của StringBuilder rất nhanh vì nó sẽ sử dụng cùng một phiên bản của đối tượng StringBuilder để thực hiện bất kỳ hoạt động nào như chèn giá trị trong chuỗi hiện có.
- StringBuilder thuộc về namespace System.Text.Stringbuilder.
42. Abstract class là gì?
Abstract modifier chỉ ra rằng thứ đang được sửa đổi có phần triển khai bị thiếu hoặc không đầy đủ. Abstract modifier có thể được sử dụng với các lớp, phương thức, thuộc tính, trình chỉ mục và sự kiện.
Một Abstract class là một lớp được ký hiệu bằng từ khóa abstract và chỉ có thể được sử dụng như một lớp cơ sở.
abstract class Shape
{
public abstract int GetArea();
}
class Square : Shape
{
int side;
public Square(int n) => side = n;
// GetArea method is required to avoid a compile-time error.
public override int GetArea() => side * side;
static void Main()
{
var sq = new Square(12);
Console.WriteLine($"Area of the square = {sq.GetArea()}");
}
}
// Output: Area of the square = 144
Abstract class có các tính năng sau:
- Một Abstract class không thể được khởi tạo.
- Một Abstract class có thể chứa các phương thức trừu tượng và trình truy cập (accessors).
- Không thể sửa đổi một Abstract class với sealed modifier vì hai modifier có ý nghĩa trái ngược nhau. Sealed modifier ngăn không cho một lớp được kế thừa và Abstract modifier yêu cầu một lớp được kế thừa.
- Một Non-abstract class được kế thừa từ một Abstract class phải bao gồm các triển khai thực tế của tất cả các phương thức và accessors được kế thừa.
43. Managed Code và Unmanaged Code là gì?
- Managed Code – Mã được phát triển trong .NET framework được gọi là managed code (mã được quản lý). Mã này được thực thi trực tiếp bởi CLR với sự trợ giúp của việc thực thi managed code. Bất kỳ ngôn ngữ nào được viết trong .NET Framework đều là managed code.
- Unmanaged Code – Mã được phát triển bên ngoài .NET framework được gọi là unmanaged code (mã không được quản lý). Các ứng dụng không chạy dưới sự kiểm soát của CLR được cho là unmanaged và một số ngôn ngữ nhất định như C++ có thể được sử dụng để viết các ứng dụng đó, chẳng hạn như truy cập các chức năng cấp thấp của hệ điều hành. Khả năng tương thích nền với mã VB, ASP và COM là những ví dụ về unmanaged code.
44. namespace trong C # là gì?
namespace được thiết kế để cung cấp một cách để giữ cho một bộ tên riêng biệt với một bộ tên khác. Các tên lớp được khai báo trong một namespace không xung đột với các tên lớp tương tự được khai báo trong một namespace khác.
- NET sử dụng namespace để tổ chức nhiều lớp của nó.
- Khai báo namespace của riêng bạn có thể giúp bạn kiểm soát phạm vi của tên lớp và phương thức trong các dự án lập trình lớn hơn.
namespace SampleNamespace
{
class SampleClass
{
public void SampleMethod()
{
System.Console.WriteLine(
"SampleMethod inside SampleNamespace");
}
}
}
45. Có thể thực thi nhiều khối lệnh catch không?
Không, không thể thực thi nhiều khối lệnh catch. Khi đoạn mã của catch thích hợp được thực thi, trình điều khiển được chuyển đến khối finally và sau đó sẽ thực thi đoạn mã của khối finally.
46. Các biến kiểu dynamic trong C # là gì?
Bạn có thể lưu trữ bất kỳ loại giá trị nào trong biến kiểu dữ liệu động (dynamic data type). Việc kiểm tra kiểu cho các loại biến này diễn ra tại runtime.
47. Serialization là gì?
Serialization có nghĩa là lưu trạng thái của đối tượng của bạn vào bộ nhớ phụ, chẳng hạn như một tệp.
- Binary serialization (Lưu dữ liệu đối tượng của bạn thành định dạng nhị phân).
- Soap Serialization (Lưu dữ liệu đối tượng của bạn thành định dạng nhị phân; chủ yếu được sử dụng trong giao tiếp liên quan đến network).
- XmlSerialization (Lưu dữ liệu đối tượng của bạn vào một tệp XML).
48. Công dụng của using trong C# là gì?
Nguyên nhân sử dụng câu lệnh using là để đảm bảo rằng đối tượng được giải phóng tài nguyên (gọi IDisposable) ngay khi nó vượt ra khỏi phạm vi và nó không yêu cầu mã rõ ràng để đảm bảo rằng điều này (việc giải phóng tài nguyên) xảy ra.
.NET CLR chuyển đổi:
using (MyResource myRes = new MyResource())
{
myRes.DoSomething();
}
thành:
{ // Limits scope of myRes
MyResource myRes= new MyResource();
try
{
myRes.DoSomething();
}
finally
{
// Check for a null resource.
if (myRes != null)
// Call the object's Dispose method.
((IDisposable)myRes).Dispose();
}
}
49. Biểu thức lambda trong C# là gì?
Biểu thức lambda là một hàm anonymous mà bạn có thể sử dụng để tạo delegate hoặc kiểu cây biểu thức. Bằng cách sử dụng biểu thức lambda, bạn có thể viết các hàm cục bộ có thể được truyền dưới dạng đối số, hoặc trả về dưới dạng giá trị của lời gọi hàm. Biểu thức lambda đặc biệt hữu ích để viết biểu thức truy vấn LINQ.
Trong ví dụ sau, biểu thức lambda x => x * x, chỉ định một tham số có tên là x và trả về giá trị của x bình phương, được gán cho một biến kiểu delegate:
Func<int, int> square = x => x * x;
Console.WriteLine(square(5));
// Output:
// 25
50. Hàm anonymous trong C# là gì?
Hàm anonymous (hàm ẩn danh) là một câu lệnh hoặc biểu thức “nội tuyến” có thể được sử dụng ở bất cứ nơi nào mong đợi một kiểu delegate. Bạn có thể sử dụng nó để khởi tạo một delegate đã đặt tên hoặc truyền nó làm tham số phương thức.
Có hai loại hàm anonymous:
- Lambda Expressions (biểu thức Lambda)
- Anonymous Methods (phương thức ẩn danh)
// Original delegate syntax required
// initialization with a named method.
TestDelegate testDelA = new TestDelegate(M);
// C# 2.0: A delegate can be initialized with
// inline code, called an "anonymous method." This
// method takes a string as an input parameter.
TestDelegate testDelB = delegate(string s) {
Console.WriteLine(s);
};
// C# 3.0. A delegate can be initialized with
// a lambda expression. The lambda also takes a string
// as an input parameter (x). The type of x is inferred by the compiler.
TestDelegate testDelC = (x) => {
Console.WriteLine(x);
};
// Invoke the delegates.
testDelA("Hello. My name is M and I write lines.");
testDelB("That's nothing. I'm anonymous and ");
testDelC("I'm a famous author.");
51. Có cách nào để bắt nhiều exception cùng một lúc và không phải duplicate mã không?
Vấn đề:
try
{
WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
WebId = Guid.Empty;
}
catch (OverflowException)
{
WebId = Guid.Empty;
}
Có cách nào để bắt cả hai exception và chỉ gọi lệnh gọi WebId = Guid.Empty một lần không?
Giải pháp:
catch (Exception ex)
{
if (ex is FormatException || ex is OverflowException)
{
WebId = Guid.Empty;
return;
}
throw;
}
52. Giải thích quá trình biên dịch mã trong C#?
Có bốn bước trong quá trình biên dịch mã bao gồm:
- Biên dịch mã nguồn thành Managed code bởi trình biên dịch C#.
- Kết hợp mã mới tạo thành các assembly.
- Tải Common Language Runtime(CLR).
- Thực thi assembly bằng CLR.
53. Sự khác biệt giữa toán tử == và phương thức Equals() trong C # là gì?
Toán tử == (thường có nghĩa giống như ReferenceEquals, có thể được ghi đè) so sánh danh tính tham chiếu, còn phương thức Equals() (virtual Equals()) so sánh nếu hai đối tượng là bằng nhau.
54. Tại sao cần sử dụng IDisposable interface?
Công dụng “chính” của IDisposable interface là dọn dẹp các tài nguyên không được quản lý. Lưu ý rằng mục đích của mẫu Dispose này là cung cấp một cơ chế để dọn dẹp cả tài nguyên được quản lý và không được quản lý và khi nào điều đó xảy ra phụ thuộc vào cách phương thức Dispose được gọi.
55. Giải thích kiểu Anonymous trong C#?
Kiểu Anonymous cho phép chúng ta tạo một kiểu mới mà không cần định nghĩa chúng. Đây là cách để xác định các thuộc tính read-only vào một đối tượng duy nhất mà không cần phải định nghĩa kiểu rõ ràng. Ở đây Type được tạo bởi trình biên dịch và nó chỉ có thể truy cập được đối với khối mã hiện tại. Loại thuộc tính cũng được suy ra bởi trình biên dịch.
var anonymousData = new
{
ForeName = "Jignesh",
SurName = "Trivedi"
};
Console.WriteLine("First Name : " + anonymousData.ForeName);
56. Sự khác biệt giữa overloading và overriding là gì?
- Overloading là khi bạn có nhiều phương thức trong cùng một phạm vi, có cùng tên nhưng khác tham số.
// Overloading
public class test
{
public void getStuff(int id) {
}
public void getStuff(string name) {
}
}
- Overriding là một nguyên tắc cho phép bạn thay đổi chức năng của một phương thức trong một lớp con.
// Overriding
public class test
{
public virtual void getStuff(int id)
{
//Get stuff default location
}
}
public class test2 : test
{
public override void getStuff(int id)
{
//base.getStuff(id);
//or - Get stuff new location
}
}
57. Đóng gói được thực hiện như thế nào trong C#?
Việc đóng gói (encapsulation) được thực hiện bằng cách sử dụng các access specifiers. Một access specifier xác định phạm vi và khả năng hiển thị của một thành viên của lớp.
- Public access specifier cho phép một lớp hiển thị các biến thành viên và các hàm thành viên của nó với các hàm và đối tượng khác. Mọi thành viên public đều có thể được truy cập từ bên ngoài lớp.
- Private access specifier cho phép một lớp ẩn các biến thành viên và các hàm thành viên của nó khỏi các hàm và đối tượng khác. Chỉ các hàm của cùng một lớp mới có thể truy cập các thành viên private của nó. Ngay cả một instance của một lớp cũng không thể truy cập vào các thành viên private của nó.
- Protected access specifier cho phép một lớp con truy cập các biến thành viên và các hàm thành viên của lớp cơ sở của nó. Bằng cách này, nó sẽ giúp thực hiện kế thừa.
58. Extension Method trong C# là gì và cách sử dụng chúng?
Các extension method (phương thức mở rộng) cho phép bạn thêm các phương thức vào các kiểu hiện có mà không cần tạo một kiểu dẫn xuất mới, biên dịch lại hoặc sửa đổi kiểu gốc.
Extension method là một loại phương thức static đặc biệt, nhưng chúng được gọi như thể chúng là các phương thức instance trên kiểu mở rộng.
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
59. Reflection trong C#.Net là gì?
Reflection là khả năng truy vấn và tương tác với hệ thống kiểu theo cách động (dynamic way). Nói chung, Reflection cho phép bạn truy cập vào metadata (siêu dữ liệu) về các đối tượng. Ví dụ, bạn có thể tải một DLL và xác định xem nó có chứa phần triển khai của một giao diện hay không. Bạn có thể sử dụng điều này để khám phá các dll hỗ trợ chức năng trong runtime. Bạn có thể sử dụng reflection để mở rộng một ứng dụng mà không cần biên dịch lại và không cần phải khởi động lại.
60. Sự khác biệt giữa Virtual method và Abstract method là gì?
- Virtual method luôn phải có một triển khai mặc định. Tuy nhiên, nó có thể được ghi đè trong lớp kế thừa, mặc dù không bắt buộc. Nó có thể được ghi đè bằng cách sử dụng từ khóa override.
- Abstract method không có phần triển khai. Nó nằm trong abstract class. Lớp kế thừa bắt buộc phải triển khai abstract method. Một từ khóa override là không cần thiết ở đây mặc dù nó có thể được sử dụng.
61. Toán tử Null Coalescing (??) được sử dụng như thế nào trong C#?
Toán tử ?? được gọi là toán tử Null Coalescing và được sử dụng để định nghĩa một giá trị mặc định cho các kiểu giá trị nullable hoặc kiểu tham chiếu. Nó trả về toán hạng bên trái nếu toán hạng không null; ngược lại, nó trả về toán hạng bên phải.
62. Phạm vi của biến thành viên Internal của một lớp C# là gì?
Internal access specifier cho phép một lớp hiển thị các biến thành viên và các hàm thành viên của nó với các hàm và đối tượng khác trong assembly hiện tại. Nói cách khác, bất kỳ thành viên nào với internal access specifier đều có thể được truy cập từ bất kỳ lớp hoặc phương thức nào được định nghĩa trong cùng ứng dụng.
public class BaseClass
{
// Only accessible within the same assembly.
internal static int x = 0;
}
Bạn có thể sử dụng nó cho các lớp / phương thức tiện ích hoặc trợ giúp mà bạn muốn truy cập từ nhiều lớp khác trong cùng một assembly, nhưng bạn muốn đảm bảo mã trong các assembly khác không thể truy cập.
63. Virtual Method trong C # là gì?
Virtual Method (phương thức ảo) là một phương thức có thể được định nghĩa lại trong các lớp dẫn xuất. Một virtual method có một triển khai trong lớp cơ sở cũng như lớp dẫn xuất. Khi một virtual method được gọi, kiểu trong runtime của đối tượng sẽ được kiểm tra xem có thành phần ghi đè hay không.
public virtual double Area()
{
return x * y;
// The implementation of a virtual member can be changed by an overriding member in a derived class.
}
- Theo mặc định, các phương thức là non-virtual. Chúng ta không thể ghi đè một phương thức non-virtual.
- Chúng ta không thể sử dụng công cụ sửa đổi virtual với các công cụ sửa đổi static, abstract, private hoặc override.
64. Có sự khác biệt giữa throw và throw ex không?
Có, giữa throw và throw ex có sự khác biệt như sau:
- Khi bạn throw ex, exception đã ném đó sẽ trở thành exception “gốc”. Vì vậy, tất cả dấu vết stack trước đó sẽ không ở đó nữa.
- Nếu bạn throw, exception chỉ đi xuống dòng và bạn sẽ nhận được dấu vết stack đầy đủ.
static void Main(string[] args)
{
try
{
Method2();
}
catch (Exception ex)
{
Console.Write(ex.StackTrace.ToString());
Console.ReadKey();
}
}
private static void Method2()
{
try
{
Method1();
}
catch (Exception ex)
{
//throw ex resets the stack trace Coming from Method 1 and propogates it to the
caller(Main)
throw ex;
}
}
private static void Method1()
{
try
{
throw new Exception("Inside Method1");
}
catch (Exception)
{
throw;
}
}
65. Làm thế nào để một lớp không bị ghi đè trong C#?
Bạn có thể ngăn một lớp khỏi bị ghi đè trong C# bằng cách sử dụng từ khóa sealed.
66. Sự khác biệt giữa từ khóa ref và out là gì?
- ref cho trình biên dịch biết rằng đối tượng được khởi tạo trước khi vào hàm, trong khi
- out cho trình biên dịch biết rằng đối tượng sẽ được khởi tạo bên trong hàm.
Vì vậy, trong khi ref là two-ways, thì out là out-only.
67. Sự khác biệt giữa biến kiểu dynamic và biến kiểu object là gì?
- Kiểu object là một alias (bí danh) cho System.Object trong .NET. Trong hệ thống kiểu thống nhất của C#, tất cả các kiểu, được xác định trước và do người dùng định nghĩa, kiểu tham chiếu và kiểu giá trị, đều kế thừa trực tiếp hoặc gián tiếp từ System.Object. Bạn có thể gán giá trị của bất kỳ kiểu nào cho các biến kiểu object.
- Kiểu dynamic chỉ ra rằng việc sử dụng biến và các tham chiếu đến các thành viên của nó sẽ bỏ qua việc kiểm tra kiểu compile-time. Thay vào đó, các hoạt động này được giải quyết tại runtime. Kiểu dynamic đơn giản hóa quyền truy cập vào các COM APIs như Office Automation APIs, tới các dynamic API như thư viện IronPython và vào HTML Document Object Model (DOM).
- Kiểu dynamic hoạt động giống như kiểu object trong hầu hết các trường hợp. Đặc biệt, bất kỳ biểu thức non-null nào cũng có thể được chuyển đổi thành kiểu dynamic. Kiểu dynamic khác với object ở chỗ các thao tác có chứa biểu thức kiểu dynamic không được giải quyết hoặc kiểm tra kiểu bởi trình biên dịch. Trình biên dịch đóng gói thông tin về hoạt động và thông tin này sau đó được sử dụng để đánh giá hoạt động tại runtime. Là một phần của quá trình, các biến của kiểu dynamic được biên dịch thành các biến của kiểu object. Do đó, kiểu dynamic chỉ tồn tại ở thời gian biên dịch, không tồn tại ở runtime.
Giả sử chúng ta có phương thức sau:
public static void ConsoleWrite(string inputArg)
{
Console.WriteLine(inputArg);
}
object: đoạn mã sau có lỗi biên dịch trừ khi truyền đối tượng thành chuỗi:
public static void Main(string[] args)
{
object obj = "String Sample";
ConsoleWrite(obj);// compile error
ConsoleWrite((string)obj); // correct
Console.ReadKey();
}
dynamic: mã sau đây biên dịch thành công nhưng nếu nó chứa một giá trị không phải string, nó sẽ tạo ra lỗi Runtime.
public static void Main(string[] args)
{
dynamic dyn = "String Sample";
ConsoleWrite(dyn); // correct
dyn = 1;
ConsoleWrite(dyn);// Runtime Error
Console.ReadKey();
}
68. Sự khác biệt giữa constant và readonly là gì?
Ngoài sự khác biệt rõ ràng là
- phải khai báo giá trị tại thời điểm định nghĩa cho một const so với các giá trị readonly có thể được tính toán động nhưng cần được gán trước khi phương thức khởi tạo thoát ra … sau đó nó bị đóng băng (frozen).
- const là hoàn toàn static. Bạn sử dụng ký hiệu ClassName.ConstantName để truy cập chúng.
còn có một sự khác biệt tinh tế, hãy xem xét lớp được định nghĩa trong AssemblyA.
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB tham chiếu đến AssemblyA và sử dụng các giá trị này trong mã. Khi điều này được biên dịch,
- trong trường hợp của giá trị const, nó giống như một tìm kiếm thay thế (find-replace), giá trị 2 được ‘đưa vào’ IL của AssemblyB. Điều này có nghĩa là nếu ngày mai, chúng ta cập nhật I_CONST_VALUE trong AssemblyA thành 20, thì I_CONST_VALUE trong AssemblyB vẫn là 2 cho đến khi chúng ta biên dịch lại nó.
- trong trường hợp của giá trị readonly, nó giống như một tham chiếu đến một vị trí bộ nhớ. Giá trị không được đưa vào IL của AssemblyB. Điều này có nghĩa là nếu vị trí bộ nhớ được cập nhật, AssemblyB sẽ nhận được giá trị mới mà không cần biên dịch lại. Vì vậy, nếu I_RO_VALUE được cập nhật thành 30, bạn chỉ cần build AssemblyA. Tất cả các client không cần phải được biên dịch lại.
Hãy nhớ rằng: Nếu bạn tham chiếu một const từ một assembly khác, giá trị của nó sẽ được biên dịch ngay trong assembly đang gọi. Bằng cách đó, khi bạn cập nhật const trong assembly được tham chiếu, nó sẽ không thay đổi trong assembly đang gọi!
69. Giải thích sự khác biệt giữa Task và Thread trong .NET?
- Thread đại diện cho một thread cấp hệ điều hành thực tế, với stack và tài nguyên hạt nhân (kernel) của riêng nó. Thread cho phép mức độ kiểm soát cao nhất; bạn có thể Abort() hoặc Suspend() hoặc Resume() một thread, bạn có thể quan sát trạng thái (state) của nó và bạn có thể đặt các thuộc tính cấp thread như stack size, state hoặc culture. ThreadPool là một trình bao bọc xung quanh một nhóm các thread được duy trì bởi CLR.
- Lớp Task từ Task Parallel Library cung cấp những gì tốt nhất của cả hai thế giới. Giống như ThreadPool, một task không tạo thread hệ điều hành của riêng nó. Thay vào đó, các task được thực thi bởi TaskScheduler; bộ lập lịch mặc định chỉ chạy trên ThreadPool. Không giống như ThreadPool, Task cũng cho phép bạn biết được khi nào nó hoàn thành và (thông qua generic Task) để trả về kết quả.
70. Tại sao bạn không thể chỉ định accessibility modifier cho các phương thức bên trong Interface?
Trong một interface, chúng ta có các phương thức ảo (virtual method) không có định nghĩa phương thức. Tất cả các phương thức ở đó sẽ được ghi đè trong lớp dẫn xuất. Đó là lý do tại sao tất cả chúng đều là public.
71. Lớp sealed trong C# là gì?
- Khi một lớp được định nghĩa là một lớp sealed, thì lớp đó không thể được kế thừa.
- Các struct cũng được sealed.