Câu hỏi Các tính năng ẩn của C #? [đã đóng]


Điều này đến với tâm trí của tôi sau khi tôi đã học được những điều sau đây từ câu hỏi này:

where T : struct

Chúng tôi, C # phát triển, tất cả biết những điều cơ bản của C #. Tôi có nghĩa là khai báo, điều kiện, vòng lặp, toán tử, v.v.

Một số người trong chúng ta thậm chí còn làm chủ được những thứ như Generics, các loại ẩn danh, lambdas, LINQ, ...

Nhưng những tính năng hay thủ thuật ẩn giấu nhất của C # mà ngay cả C #, người nghiện, chuyên gia hầu như không biết?

Dưới đây là các tính năng được tiết lộ cho đến thời điểm này:


Từ khóa

Thuộc tính

Cú pháp

  • ?? toán tử (coalesce nulls) bởi kokos
  • Số lá cờ của Nick Berardi
  • where T:new bởi Lars Mæhlum
  • Ngụ ý ngầm bằng Keith
  • Lambdas một tham số bằng Keith
  • Thuộc tính tự động theo Keith
  • Bí danh không gian tên của Keith
  • Nguyên văn chuỗi ký tự bằng @ by Patrick
  • enum giá trị bởi lfoust
  • @variablenames bởi marxidad
  • event toán tử bởi marxidad
  • Định dạng dấu ngoặc đơn bằng Portman
  • Công cụ sửa đổi truy cập thuộc tính truy cập theo xanadont
  • Toán tử điều kiện (ternary) (?:) bởi JasonS
  • checked và unchecked toán tử bởi Binoj Antony
  • implicit and explicit toán tử bởi Flory

Tính năng ngôn ngữ

Các tính năng của Visual Studio

  • Chọn khối văn bản trong trình chỉnh sửa theo Himadri
  • Đoạn trích bởi DannySmurf 

Khung

Phương thức và thuộc tính

  • String.IsNullOrEmpty() phương pháp của KiwiBastard
  • List.ForEach() phương pháp của KiwiBastard
  • BeginInvoke(), EndInvoke() phương pháp của Will Dean
  • Nullable<T>.HasValue và Nullable<T>.Value tính chất của Rismo
  • GetValueOrDefault phương pháp của John Sheehan

Mẹo & thủ thuật

  • Phương pháp tốt cho trình xử lý sự kiện theo Andreas H.R. Nilsson
  • So sánh chữ hoa bằng John
  • Truy cập các loại vô danh mà không bị phản ánh bởi dp
  • Một cách nhanh chóng để lười biếng khởi tạo các thuộc tính thu thập theo Sẽ
  • Các hàm nội tuyến ẩn danh giống như JavaScript roosteronacid

Khác


1476


gốc




Các câu trả lời:


Đây không phải là C #, nhưng tôi chưa từng thấy ai thực sự sử dụng System.IO.Path.Combine() đến mức mà họ cần. Trên thực tế, toàn bộ lớp Path thực sự hữu ích, nhưng không ai sử dụng nó!

Tôi sẵn sàng đặt cược rằng mọi ứng dụng sản xuất đều có mã sau, mặc dù nó không nên:

string path = dir + "\\" + fileName;

752





lambdas và loại inferrence được đánh giá thấp. Lambdas có thể có nhiều câu lệnh và họ gấp đôi như một đối tượng đại biểu tương thích tự động (chỉ cần đảm bảo khớp chữ ký) như sau:

Console.CancelKeyPress +=
    (sender, e) => {
        Console.WriteLine("CTRL+C detected!\n");
        e.Cancel = true;
    };

Lưu ý rằng tôi không có new CancellationEventHandler tôi cũng không phải chỉ định các loại sender và e, họ không thể tránh khỏi sự kiện này. Đó là lý do tại sao điều này ít cồng kềnh hơn để viết toàn bộ delegate (blah blah) cũng yêu cầu bạn chỉ định các loại tham số.

Lambdas không cần phải trả lại bất cứ điều gì và suy luận kiểu là cực kỳ mạnh mẽ trong ngữ cảnh như thế này.

Và BTW, bạn luôn có thể quay trở lại Lambdas làm Lambdas theo nghĩa lập trình chức năng. Ví dụ, đây là một lambda mà làm cho một lambda xử lý một sự kiện Button.Click:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

Lưu ý chuỗi: (dx, dy) => (sender, e) =>

Bây giờ đó là lý do tại sao tôi rất vui khi đã tham gia lớp lập trình chức năng :-)

Khác với các con trỏ trong C, tôi nghĩ rằng đó là điều cơ bản khác bạn nên học :-)


585





Từ Rick Strahl:

Bạn có thể chuỗi ?? toán tử để bạn có thể thực hiện một loạt các so sánh null.

string result = value1 ?? value2 ?? value3 ?? String.Empty;

528





Generics thiên vị:

using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;

Nó cho phép bạn sử dụng ASimpleName, thay vì Dictionary<string, Dictionary<string, List<string>>>.

Sử dụng nó khi bạn sẽ sử dụng cùng một điều phức tạp dài chung chung ở rất nhiều nơi.


455





Từ CLR qua C #:

Khi bình thường hóa chuỗi, nó rất cao   đề nghị bạn sử dụng   ToUpperInvariant thay vì   ToLowerInvariant vì Microsoft có   đã tối ưu hóa mã để thực hiện   so sánh chữ hoa.

Tôi nhớ một lần đồng nghiệp của tôi luôn thay đổi dây thành chữ hoa trước khi so sánh. Tôi đã luôn luôn tự hỏi tại sao anh ấy làm điều đó bởi vì tôi cảm thấy nó "tự nhiên" hơn để chuyển đổi sang chữ thường đầu tiên. Sau khi đọc cuốn sách bây giờ tôi biết tại sao.


438



Khi bạn "chuyển đổi chuỗi thành chữ hoa" bạn tạo một đối tượng chuỗi tạm thời thứ hai. Tôi nghĩ rằng loại so sánh này không được ưa thích, rằng cách tốt nhất là: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase) whcih không tạo ra chuỗi ném này cả. - Anthony
Bạn có thể thực hiện loại tối ưu nào khi so sánh các chuỗi chữ hoa trên không thể thực hiện trên các chuỗi chữ thường? Tôi không hiểu tại sao người ta sẽ tối ưu hơn người kia. - Parappa
Chuyển đổi sang chữ hoa thay vì chữ thường cũng có thể ngăn chặn hành vi không chính xác trong một số nền văn hóa nhất định. Ví dụ, trong tiếng Thổ Nhĩ Kỳ, hai chữ thường i của bản đồ để cùng một chữ hoa I. Google "Thổ Nhĩ Kỳ tôi" để biết thêm chi tiết. - Neil
Tôi đã thử điểm chuẩn ToUpperInvariant vs ToLowerInvariant. Tôi không thể tìm thấy bất kỳ sự khác biệt nào về hiệu suất của chúng trong .NET 2.0 hoặc 3.5. Chắc chắn không phải bất cứ điều gì mà đảm bảo "rất khuyến khích" bằng cách sử dụng một trong khác. - Rasmus Faber
ToUpperInvariant được ưa thích bởi vì nó làm cho tất cả các nhân vật trong chuyến đi khứ hồi. Xem msdn.microsoft.com/en-us/library/bb386042.aspx. Để so sánh, viết"a".Equals("A", StringComparison.OrdinalIgnoreCase) - SLaks


Bí quyết yêu thích của tôi là sử dụng toán tử kết hợp rỗng và dấu ngoặc đơn để tự động hóa các bộ sưu tập cho tôi.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }

409



Bạn không thấy khó đọc? - Riri
Hơi khó đọc của nó cho noo ... er, thiếu kinh nghiệm. Nhưng nó nhỏ gọn và chứa một vài mẫu và các tính năng ngôn ngữ mà lập trình viên nên biết và hiểu. Vì vậy, trong khi nó là khó khăn lúc đầu, nó cung cấp lợi ích của việc là một lý do để tìm hiểu. - Will
Sự khởi đầu lười biếng là một sự sơ suất vì nó là sự lựa chọn của người nghèo để tránh suy nghĩ về những bất biến của lớp. Nó cũng có vấn đề tương tranh. - John Leidegren
Tôi đã luôn luôn được thông báo đây là thực hành xấu, mà gọi một tài sản không nên làm một cái gì đó như vậy. Nếu bạn có một tập hợp trên đó và đặt giá trị thành null, sẽ rất lạ đối với người nào đó đang sử dụng API của bạn. - Ian
@ Jelel ngoại trừ việc thiết lập ListOfFoo thành null không phải là một phần của hợp đồng lớp cũng không phải là thực hành tốt. Đó là lý do tại sao không có một setter. Đó cũng là lý do tại sao ListOfFoo được đảm bảo trả lại một bộ sưu tập và không bao giờ là một null. Nó chỉ là một khiếu nại rất kỳ lạ rằng nếu bạn làm hai điều xấu (làm cho một setter và thiết lập một bộ sưu tập để null) điều này sẽ dẫn đến mong đợi của bạn là sai. Tôi sẽ không đề nghị làm Environment.Exit () trong getter, một trong hai. Nhưng điều đó cũng không liên quan gì đến câu trả lời này. - Will


Tránh kiểm tra các trình xử lý sự kiện null

Thêm một đại biểu trống vào các sự kiện tại khai báo, ngăn chặn sự cần thiết phải luôn luôn kiểm tra sự kiện cho null trước khi gọi nó là tuyệt vời. Thí dụ:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

Hãy để bạn làm điều này

public void DoSomething()
{
    Click(this, "foo");
}

Thay vì điều này

public void DoSomething()
{
    // Unnecessary!
    MyClickHandler click = Click;
    if (click != null) // Unnecessary! 
    {
        click(this, "foo");
    }
}

Xin vui lòng xem điều này thảo luận liên quan và cái này bài viết trên blog bởi Eric Lippert về chủ đề này (và những nhược điểm có thể xảy ra).


314



Tôi tin rằng một vấn đề sẽ xuất hiện nếu bạn dựa vào kỹ thuật này và sau đó bạn phải sắp xếp từng lớp. Bạn sẽ loại bỏ sự kiện, và sau đó trên deserialization bạn sẽ nhận được một NullRefference .... Do đó, người ta chỉ có thể dính vào "cách cũ" làm việc. Nó an toàn hơn. - sirrocco
bạn vẫn có thể đặt trình xử lý sự kiện của mình thành null, vì vậy bạn vẫn có thể nhận được tham chiếu null và bạn vẫn có điều kiện chủng tộc. - Robert Paulson
Một bài kiểm tra hồ sơ nhanh cho thấy trình xử lý sự kiện được đăng ký giả mà không có phép thử null mất khoảng 2x thời gian xử lý sự kiện chưa được đăng ký với kiểm tra null. Trình xử lý sự kiện Multicast không có kiểm tra null mất khoảng 3.5 lần thời gian xử lý sự kiện singlecast với kiểm tra null. - P Daddy
Điều này tránh sự cần thiết cho một kiểm tra null bởi chỉ luôn luôn có một thuê bao tự. Ngay cả khi một sự kiện trống rỗng, nó mang một chi phí mà bạn không muốn. Nếu không có người đăng ký nào bạn không muốn kích hoạt sự kiện, không phải lúc nào cũng kích hoạt sự kiện giả trống. Tôi sẽ xem xét mã xấu này. - Keith
Đây là một gợi ý khủng khiếp, vì những lý do trong các bình luận trên. Nếu bạn phải làm cho mã của bạn trông "sạch", sử dụng một phương pháp mở rộng để kiểm tra null sau đó gọi sự kiện. Người nào đó có đặc quyền sửa đổi chắc chắn nên thêm nhược điểm cho câu trả lời này. - Greg


Mọi thứ khác, cộng

1) generics ngầm (tại sao chỉ trên phương pháp và không phải trên các lớp học?)

void GenericMethod<T>( T input ) { ... }

//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23);      //Is enough.

2) lambdas đơn giản với một tham số:

x => x.ToString() //simplify so many calls

3) loại vô danh và khởi tạo:

//Duck-typed: works with any .Add method.
var colours = new Dictionary<string, string> {
    { "red", "#ff0000" },
    { "green", "#00ff00" },
    { "blue", "#0000ff" }
};

int[] arrayOfInt = { 1, 2, 3, 4, 5 };

Một số khác:

4) Thuộc tính tự động có thể có các phạm vi khác nhau:

public int MyId { get; private set; }

Cảm ơn @pzycoman đã nhắc tôi:

5) Bí danh không gian tên (không phải là bạn có khả năng cần sự phân biệt cụ thể này):

using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();

305



trong # 3 bạn có thể làm Enumerable.Range (1,5) - Echostorm
tôi nghĩ rằng bạn đã có thể khởi tạo mảng với int [] nums = {1,2,3}; kể từ 1.0 :) thậm chí không cần từ khóa "mới" - Lucas
lambda cũng không có tham số () => DoSomething (); - Pablo Retyk
Tôi đã sử dụng cả hai {get; bộ nội bộ; } và lấy; bộ bảo vệ; }, vì vậy mẫu này phù hợp. - Keith
@Kirk Broadhurst - bạn nói đúng - new web.Control() cũng sẽ làm việc trong ví dụ này. Các :: cú pháp buộc nó xử lý tiền tố như một bí danh không gian tên, vì vậy bạn có thể có một lớp được gọi là web và web::Control cú pháp sẽ vẫn hoạt động, trong khi web.Control cú pháp sẽ không biết có nên kiểm tra lớp hay không gian tên. Do đó tôi có xu hướng luôn sử dụng :: khi thực hiện bí danh không gian tên. - Keith


Tôi không biết từ khóa "như" trong một thời gian dài.

MyClass myObject = (MyClass) obj;

so với

MyClass myObject = obj as MyClass;

Thứ hai sẽ trả về null nếu obj không phải là một MyClass, chứ không phải là ném một lớp ngoại lệ.


286



Đừng quá làm điều đó mặc dù. Rất nhiều người dường như sử dụng vì thích cú pháp hơn mặc dù họ muốn ngữ nghĩa của một (ToType) x. - Scott Langham
Tôi không tin nó cung cấp hiệu suất tốt hơn. Bạn đã lược tả nó chưa? (Rõ ràng mặc dù nó diễn ra khi dàn diễn viên thất bại ... nhưng khi bạn sử dụng (MyClass) cast, thất bại là ngoại lệ .. và cực kỳ hiếm (nếu chúng xảy ra ở tất cả), do đó, nó làm cho không có sự khác biệt. - Scott Langham
Điều này chỉ có hiệu suất cao hơn nếu trường hợp thông thường là diễn viên thất bại. Nếu không thì đối tượng cast (type) trực tiếp sẽ nhanh hơn. Nó mất nhiều thời gian hơn cho một diễn viên trực tiếp để ném một ngoại lệ hơn để trả về null mặc dù. - Spence
Ngay dọc theo cùng một dòng của từ khóa "as" ... từ khóa "is" cũng hữu ích. - dkpatt
Bạn có thể lạm dụng nó và có một NullReferenceException xuống đường của bạn sau này khi bạn có thể đã có một InvalidCastException trước đó. - Andrei Rînea


Hai điều tôi thích là các thuộc tính Tự động để bạn có thể thu gọn mã của mình hơn nữa:

private string _name;
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

trở thành

public string Name { get; set;}

Ngoài ra đối tượng khởi tạo:

Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();

trở thành

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}

262



Nên lưu ý rằng tính chất tự động là một tính năng chỉ có C # 3.0? - Jared Updike
Thuộc tính tự động được giới thiệu với trình biên dịch 3.0. Nhưng vì trình biên dịch có thể được đặt thành mã đầu ra 2.0, chúng hoạt động tốt. Chỉ cần không cố gắng biên dịch mã 2.0 với các thuộc tính tự động trong trình biên dịch cũ hơn! - Joshua Shannon
Một cái gì đó nhiều người không nhận ra là nhận được và thiết lập có thể có khả năng tiếp cận khác nhau, ví dụ: public string Name {get; bộ riêng tư;} - Nader Shirazie
Chỉ có vấn đề với Thuộc tính tự động là dường như không thể cung cấp giá trị khởi tạo mặc định. - Stein Åsmul
@ Meneves: không có nó không. Từ trang đó: Một DefaultValueAttribute sẽ không làm cho một thành viên được tự động khởi tạo với giá trị của thuộc tính. Bạn phải đặt giá trị ban đầu trong mã của mình.  [DefaultValue] được sử dụng cho nhà thiết kế để nó biết có hiển thị thuộc tính in đậm (có nghĩa là không mặc định) hay không. - Roger Lipscombe


Từ khóa 'mặc định' trong các loại chung:

T t = default(T);

kết quả trong một 'null' nếu T là một kiểu tham chiếu, và 0 nếu nó là một int, false nếu nó là một boolean, v.v.


255



Plus: gõ? dưới dạng phím tắt cho Nullable <type>. mặc định (int) == 0, nhưng mặc định (int?) == null. - sunside