Chuyển đổi tuyên bố giảm trong C #?


365

Chuyển đổi tuyên bố chuyển đổi là một trong những lý do chính của cá nhân tôi để yêu thương switchso với các if/else ifcấu trúc. Một ví dụ là theo thứ tự ở đây:

static string NumberToWords(int number)
{
    string[] numbers = new string[] 
        { "", "one", "two", "three", "four", "five", 
          "six", "seven", "eight", "nine" };
    string[] tens = new string[] 
        { "", "", "twenty", "thirty", "forty", "fifty", 
          "sixty", "seventy", "eighty", "ninety" };
    string[] teens = new string[]
        { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
          "sixteen", "seventeen", "eighteen", "nineteen" };

    string ans = "";
    switch (number.ToString().Length)
    {
        case 3:
            ans += string.Format("{0} hundred and ", numbers[number / 100]);
        case 2:
            int t = (number / 10) % 10;
            if (t == 1)
            {
                ans += teens[number % 10];
                break;
            }
            else if (t > 1)
                ans += string.Format("{0}-", tens[t]);
        case 1:
            int o = number % 10;
            ans += numbers[o];

            break;
        default:
            throw new ArgumentException("number");
    }
    return ans;
}

Những người thông minh đang co rúm lại vì string[]s nên được khai báo bên ngoài chức năng: tốt, họ là, đây chỉ là một ví dụ.

Trình biên dịch thất bại với lỗi sau:

Kiểm soát không thể rơi từ nhãn trường hợp này ('trường hợp 3:') sang nhãn khác
Kiểm soát không thể rơi từ nhãn trường hợp này ('trường hợp 2:') sang nhãn khác

Tại sao? Và có cách nào để có được loại hành vi này mà không có ba ifs không?

Câu trả lời:


648

(Sao chép / dán câu trả lời tôi cung cấp ở nơi khác )

Rơi qua switch- casecó thể đạt được bằng cách không có mã trong một case(xem case 0) hoặc sử dụng các hình thức đặc biệt goto case(xem case 1) hoặc goto default(xem case 2):

switch (/*...*/) {
    case 0: // shares the exact same code as case 1
    case 1:
        // do something
        goto case 2;
    case 2:
        // do something else
        goto default;
    default:
        // do something entirely different
        break;
}

121
Tôi nghĩ rằng, trong trường hợp cụ thể này, goto không được coi là có hại.
Thomas Owens

78
Chết tiệt - Tôi đã lập trình với C # từ những ngày đầu tiên của 1.0 và tôi chưa bao giờ thấy điều này cho đến bây giờ. Chỉ cần đi để hiển thị, bạn học những điều mới mỗi ngày.
Erik Forbes

37
Tất cả đều tốt, Erik. Lý do duy nhất / tôi / biết về nó là lý thuyết trình biên dịch của tôi, người đã đọc thông số kỹ thuật ECMA-334 với kính lúp.
Alex Lyman

13
@Dancrumb: Tại thời điểm tính năng được viết, C # chưa thêm bất kỳ từ khóa "mềm" nào (như 'suất', 'var', 'từ' và 'select'), vì vậy họ có ba tùy chọn thực tế: 1 ) biến 'fallistic' thành một từ khóa cứng (bạn không thể sử dụng nó làm tên biến), 2) viết mã cần thiết để hỗ trợ một từ khóa mềm như vậy, 3) sử dụng các từ khóa đã dành riêng. # 1 là một vấn đề lớn đối với các mã porting; # 2 là một nhiệm vụ kỹ thuật khá lớn, từ những gì tôi hiểu; và tùy chọn họ đã đi cùng, # 3 có một lợi ích phụ: các nhà phát triển khác đọc mã sau khi thực tế có thể tìm hiểu về tính năng từ khái niệm cơ bản của goto
Alex Lyman

10
Tất cả điều này nói về các từ khóa mới / đặc biệt cho một sự sụp đổ rõ ràng. Họ không thể sử dụng từ khóa 'tiếp tục' sao? Nói cách khác. Thoát khỏi công tắc hoặc tiếp tục vào trường hợp tiếp theo (rơi qua).
Tal thậm chí-Tov

44

"Tại sao" là để tránh sự cố tình cờ, mà tôi biết ơn. Đây là một nguồn lỗi không phổ biến trong C và Java.

Cách giải quyết là sử dụng goto, vd

switch (number.ToString().Length)
{
    case 3:
        ans += string.Format("{0} hundred and ", numbers[number / 100]);
        goto case 2;
    case 2:
    // Etc
}

Thiết kế chung của switch / case là một chút không may trong quan điểm của tôi. Nó bị mắc kẹt quá gần với C - có một số thay đổi hữu ích có thể được thực hiện theo phạm vi, v.v. Có thể cho rằng một công tắc thông minh hơn có thể thực hiện khớp mẫu, v.v ... sẽ hữu ích, nhưng thực sự thay đổi từ chuyển sang "kiểm tra chuỗi điều kiện" - tại thời điểm đó, một tên khác có lẽ sẽ được gọi cho.


1
Đây là sự khác biệt giữa chuyển đổi và if / otherif trong tâm trí của tôi. Switch là để kiểm tra các trạng thái khác nhau của một biến, trong khi if / otherif có thể được sử dụng để kiểm tra bất kỳ số lượng nào được kết nối, nhưng không nhất thiết là một biến hoặc cùng một biến.
Matthew Scharley

2
Nếu đó là để ngăn chặn tình cờ rơi vào thì tôi cảm thấy một cảnh báo trình biên dịch sẽ tốt hơn. Giống như bạn có một câu lệnh if nếu câu lệnh if của bạn có một bài tập:if (result = true) { }
Tal Thậm chí-Tov

3
@ TalEven-Tov: Cảnh báo trình biên dịch nên thực sự dành cho các trường hợp bạn hầu như luôn có thể sửa mã để tốt hơn. Cá nhân tôi muốn phá vỡ ngầm, vì vậy nó sẽ không phải là một vấn đề để bắt đầu, nhưng đó là một vấn đề khác.
Jon Skeet

26

Chuyển đổi dự phòng là một trong những nguồn lỗi chính trong các phần mềm hiện đại. Nhà thiết kế ngôn ngữ đã quyết định bắt buộc phải nhảy vào cuối vụ án, trừ khi bạn trực tiếp mặc định cho trường hợp tiếp theo mà không xử lý.

switch(value)
{
    case 1:// this is still legal
    case 2:
}

23
Tôi cũng không bao giờ hiểu tại sao đó không phải là "trường hợp 1, 2:"
BCS

11
@David Pfeffer: Đúng vậy, và case 1, 2:trong các ngôn ngữ cho phép điều đó. Điều tôi sẽ không bao giờ hiểu là tại sao bất kỳ ngôn ngữ hiện đại nào sẽ không chọn cho phép điều đó.
BCS

@BCS với câu lệnh goto, nhiều tùy chọn được phân tách bằng dấu phẩy có thể khó xử lý?
penguat

@pengut: có thể chính xác hơn để nói rằng đó case 1, 2:là một nhãn duy nhất nhưng có nhiều tên. - F. thêm) trường hợp nhãn là một bước nhảy.
BCS

22

Để thêm vào câu trả lời ở đây, tôi nghĩ rằng đáng để xem xét câu hỏi ngược lại kết hợp với điều này, viz. Tại sao C cho phép rơi xuống ở nơi đầu tiên?

Bất kỳ ngôn ngữ lập trình tất nhiên đều phục vụ hai mục tiêu:

  1. Cung cấp hướng dẫn cho máy tính.
  2. Để lại một hồ sơ về ý định của lập trình viên.

Do đó, việc tạo ra bất kỳ ngôn ngữ lập trình nào là sự cân bằng giữa cách phục vụ tốt nhất hai mục tiêu này. Một mặt, việc biến thành các hướng dẫn máy tính càng dễ dàng hơn (cho dù đó là mã máy, mã byte như IL hay hướng dẫn được diễn giải khi thực hiện) thì quá trình biên dịch hoặc giải thích sẽ có hiệu quả, đáng tin cậy và đầu ra nhỏ gọn. Thực hiện đến cùng cực, mục tiêu này dẫn đến việc chúng ta chỉ viết bằng cách lắp ráp, IL hoặc thậm chí là mã op thô, bởi vì phần biên dịch đơn giản nhất là ở đó không có phần biên dịch nào cả.

Ngược lại, ngôn ngữ càng thể hiện ý định của lập trình viên, thay vì các phương tiện được đưa đến mục đích đó, chương trình càng dễ hiểu hơn cả khi viết và trong khi bảo trì.

Bây giờ, switchluôn có thể được biên dịch bằng cách chuyển đổi nó thành chuỗi if-elsekhối tương đương hoặc tương tự, nhưng nó được thiết kế để cho phép biên dịch thành một mô hình lắp ráp chung cụ thể trong đó người ta lấy một giá trị, tính toán một phần bù từ nó (cho dù bằng cách tra cứu bảng được lập chỉ mục bởi một hàm băm hoàn hảo của giá trị hoặc theo số học thực tế trên giá trị *). Điều đáng chú ý ở thời điểm này là ngày nay, quá trình biên dịch C # đôi khi sẽ chuyển switchthành tương đương if-elsevà đôi khi sử dụng cách tiếp cận nhảy dựa trên hàm băm (và tương tự với C, C ++ và các ngôn ngữ khác có cú pháp tương đương).

Trong trường hợp này, có hai lý do chính đáng để cho phép thông qua:

  1. Dù sao nó cũng chỉ xảy ra một cách tự nhiên: nếu bạn xây dựng một bảng nhảy thành một tập hợp các hướng dẫn và một trong những hướng dẫn trước đó không chứa một số bước nhảy hoặc trả về, thì việc thực thi sẽ tự nhiên tiến triển thành đợt tiếp theo. Cho phép rơi xuống là điều sẽ "chỉ xảy ra" nếu bạn biến switchC sử dụng thành bảng nhảy bằng cách sử dụng mã máy.

  2. Các lập trình viên đã viết trong phần lắp ráp đã được sử dụng tương đương: khi viết một bảng nhảy bằng tay trong phần lắp ráp, họ sẽ phải xem xét liệu một khối mã đã cho có kết thúc bằng một sự trở lại, một bước nhảy ra khỏi bảng hay chỉ tiếp tục đến khối tiếp theo. Như vậy, việc lập trình viên thêm một phần rõ ràng breakkhi cần thiết là "tự nhiên" đối với người viết mã.

Do đó, tại thời điểm đó, đây là một nỗ lực hợp lý để cân bằng hai mục tiêu của ngôn ngữ máy tính vì nó liên quan đến cả mã máy được sản xuất và tính biểu cảm của mã nguồn.

Bốn thập kỷ sau, mọi thứ không hoàn toàn giống nhau, vì một vài lý do:

  1. Coders trong C ngày nay có thể có ít hoặc không có kinh nghiệm lắp ráp. Các lập trình viên trong nhiều ngôn ngữ kiểu C khác thậm chí ít có khả năng hơn (đặc biệt là Javascript!). Mọi khái niệm về "những gì mọi người đã sử dụng để lắp ráp" không còn phù hợp.
  2. Những cải tiến trong tối ưu hóa có nghĩa là khả năng switchbị biến thành if-elsebởi vì nó được coi là phương pháp có khả năng hiệu quả nhất, hoặc nếu không thì biến thành một biến thể bí truyền đặc biệt của phương pháp nhảy bàn là cao hơn. Ánh xạ giữa các cách tiếp cận cấp cao hơn và cấp thấp hơn không mạnh như trước đây.
  3. Kinh nghiệm đã chỉ ra rằng rơi xuống có xu hướng là trường hợp thiểu số chứ không phải là tiêu chuẩn (một nghiên cứu về trình biên dịch của Sun đã tìm thấy 3% switchkhối được sử dụng khác với nhiều nhãn trên cùng một khối và người ta cho rằng việc sử dụng- trường hợp ở đây có nghĩa là 3% này thực tế cao hơn nhiều so với bình thường). Vì vậy, ngôn ngữ được nghiên cứu làm cho sự khác thường dễ phục vụ hơn so với thông thường.
  4. Kinh nghiệm đã chỉ ra rằng việc rơi qua có xu hướng là nguồn gốc của các vấn đề cả trong trường hợp nó vô tình được thực hiện và cả trong trường hợp rơi đúng cách bị ai đó duy trì mã. Cái sau này là một bổ sung tinh tế cho các lỗi liên quan đến sự cố, bởi vì ngay cả khi mã của bạn hoàn toàn không có lỗi, sự cố của bạn vẫn có thể gây ra sự cố.

Liên quan đến hai điểm cuối cùng, hãy xem xét trích dẫn sau từ phiên bản hiện tại của K & R:

Rơi xuống từ trường hợp này sang trường hợp khác là không mạnh mẽ, dễ bị tan rã khi chương trình được sửa đổi. Ngoại trừ nhiều nhãn cho một tính toán duy nhất, thông qua nên được sử dụng một cách tiết kiệm và nhận xét.

Là một vấn đề về hình thức tốt, hãy tạm dừng sau trường hợp cuối cùng (mặc định ở đây) mặc dù điều đó không cần thiết về mặt logic. Một ngày nào đó khi một trường hợp khác được thêm vào cuối, một chút lập trình phòng thủ này sẽ cứu bạn.

Vì vậy, từ miệng ngựa, rơi vào C là có vấn đề. Nó được coi là một cách thực hành tốt để luôn ghi lại các thông tin bằng các bình luận, đó là một ứng dụng của nguyên tắc chung mà người ta nên ghi lại khi một người làm điều gì đó bất thường, bởi vì đó là điều sẽ xảy ra sau khi kiểm tra mã và / hoặc làm cho mã của bạn trông giống như vậy có một lỗi của người mới trong khi nó thực sự đúng.

Và khi bạn nghĩ về nó, mã như thế này:

switch(x)
{
  case 1:
   foo();
   /* FALLTHRU */
  case 2:
    bar();
    break;
}

Việc thêm một cái gì đó để làm cho thông tin rõ ràng trong mã, nó không phải là thứ gì đó có thể được phát hiện (hoặc sự vắng mặt của nó có thể được phát hiện) bởi trình biên dịch.

Như vậy, thực tế là phải rõ ràng với thông báo rơi vào C # không thêm bất kỳ hình phạt nào cho những người viết tốt bằng các ngôn ngữ kiểu C khác, vì họ sẽ rõ ràng trong các lần rơi của họ.

Cuối cùng, việc sử dụng gotoở đây đã là một chuẩn mực từ C và các ngôn ngữ khác:

switch(x)
{
  case 0:
  case 1:
  case 2:
    foo();
    goto below_six;
  case 3:
    bar();
    goto below_six;
  case 4:
    baz();
    /* FALLTHRU */
  case 5:
  below_six:
    qux();
    break;
  default:
    quux();
}

Trong trường hợp này, trong đó chúng tôi muốn một khối được bao gồm trong mã được thực thi cho một giá trị khác với khối mang đến một khối trước đó, thì chúng tôi đã phải sử dụng goto. (Tất nhiên, có những cách và cách để tránh điều này với các điều kiện khác nhau nhưng điều đó đúng với mọi thứ liên quan đến câu hỏi này). Vì vậy, C # được xây dựng theo cách đã bình thường để đối phó với một tình huống trong đó chúng tôi muốn đạt được nhiều hơn một khối mã trong một switch, và chỉ khái quát hóa nó để bao quát cả sự sụp đổ. Nó cũng làm cho cả hai trường hợp thuận tiện hơn và tự ghi lại tài liệu, vì chúng ta phải thêm nhãn mới trong C nhưng có thể sử dụng caselàm nhãn trong C #. Trong C #, chúng ta có thể thoát khỏi below_sixnhãn và sử dụng goto case 5rõ ràng hơn những gì chúng ta đang làm. (Chúng tôi cũng phải thêmbreakđối với default, cái mà tôi đã bỏ qua chỉ để làm cho mã C ở trên rõ ràng không phải là mã C #).

Tóm lại:

  1. C # không còn liên quan đến đầu ra của trình biên dịch không được tối ưu hóa như mã C đã làm cách đây 40 năm (cũng như C ngày nay), điều này làm cho một trong những nguồn cảm hứng của sự sụp đổ không liên quan.
  2. C # vẫn tương thích với C không chỉ ẩn break, để học ngôn ngữ dễ dàng hơn bởi những người quen thuộc với các ngôn ngữ tương tự và chuyển dễ dàng hơn.
  3. C # loại bỏ một nguồn có thể có lỗi hoặc mã bị hiểu lầm đã được ghi nhận tốt là gây ra vấn đề trong bốn thập kỷ qua.
  4. C # làm cho thực tiễn tốt nhất hiện có với C (tài liệu rơi qua) được thực thi bởi trình biên dịch.
  5. C # làm cho trường hợp bất thường trở thành trường hợp có mã rõ ràng hơn, trường hợp thông thường là trường hợp có mã chỉ ghi tự động.
  6. C # sử dụng gotocách tiếp cận dựa trên cùng một cách để đánh cùng một khối từ các casenhãn khác nhau như được sử dụng trong C. Nó chỉ khái quát nó cho một số trường hợp khác.
  7. C # làm cho gotocách tiếp cận dựa trên đó thuận tiện hơn và rõ ràng hơn so với trong C, bằng cách cho phép các casecâu lệnh đóng vai trò là nhãn.

Tất cả trong tất cả, một quyết định thiết kế khá hợp lý


* Một số hình thức BASIC sẽ cho phép một người thực hiện những GOTO (x AND 7) * 50 + 240điều tương tự trong khi dễ vỡ và do đó, một trường hợp đặc biệt thuyết phục để cấm goto, sẽ phục vụ để hiển thị một ngôn ngữ cao hơn tương tự như cách mà mã cấp thấp hơn có thể thực hiện bước nhảy dựa trên số học dựa trên một giá trị, hợp lý hơn nhiều khi đó là kết quả của quá trình biên dịch thay vì một cái gì đó phải được duy trì bằng tay. Việc triển khai Thiết bị của Duff nói riêng cho vay chính xác mã máy tương đương hoặc IL vì mỗi khối hướng dẫn thường sẽ có cùng độ dài mà không cần thêm nopchất độn.

Device Thiết bị của Duff trở lại đây một lần nữa, như một ngoại lệ hợp lý. Thực tế là với mô hình tương tự và tương tự đó, có một sự lặp lại của các hoạt động phục vụ cho việc sử dụng thông qua tương đối rõ ràng ngay cả khi không có nhận xét rõ ràng về hiệu ứng đó.


17

Bạn có thể 'nhãn trường hợp goto' http://www.blackwasp.co.uk/CSharpGoto.aspx

Câu lệnh goto là một lệnh đơn giản chuyển vô điều khiển chương trình sang câu lệnh khác. Lệnh này thường bị chỉ trích với một số nhà phát triển ủng hộ việc loại bỏ nó khỏi tất cả các ngôn ngữ lập trình cấp cao vì nó có thể dẫn đến mã spaghetti . Điều này xảy ra khi có rất nhiều câu lệnh goto hoặc câu lệnh nhảy tương tự khiến mã trở nên khó đọc và duy trì. Tuy nhiên, có những lập trình viên chỉ ra rằng câu lệnh goto, khi được sử dụng cẩn thận, cung cấp một giải pháp tao nhã cho một số vấn đề ...


8

Họ đã bỏ qua hành vi này bằng thiết kế để tránh khi nó không được sử dụng bởi ý chí nhưng gây ra vấn đề.

Nó chỉ có thể được sử dụng nếu không có câu lệnh nào trong phần trường hợp, như:

switch (whatever)
{
    case 1:
    case 2:
    case 3: boo; break;
}

4

Họ đã thay đổi hành vi câu lệnh switch (từ C / Java / C ++) cho c #. Tôi đoán lý do là mọi người quên mất việc rơi và lỗi đã gây ra. Một cuốn sách tôi đọc nói sử dụng goto để mô phỏng, nhưng điều này nghe có vẻ không phải là một giải pháp tốt cho tôi.


2
C # hỗ trợ goto, nhưng không sai lầm? Ồ Và đó không chỉ là những thứ đó. C # là ngôn ngữ duy nhất mà tôi biết hành xử theo cách này.
Matthew Scharley

Ban đầu tôi không thích nó, nhưng "fall-thru" thực sự là một công thức cho thảm họa (đặc biệt là trong số các lập trình viên cơ sở.) Như nhiều người đã chỉ ra, C # vẫn cho phép fall-thru cho các dòng trống (phần lớn là trường hợp.) "Kenny" đã đăng một liên kết làm nổi bật việc sử dụng Goto thanh lịch với trường hợp chuyển đổi.
Pretzel

Đó không phải là một vấn đề lớn trong quan điểm của tôi. 99% thời gian tôi không muốn bị ngã và tôi đã bị đốt bởi những con bọ trong quá khứ.
Ken

1
"Đây không phải là một giải pháp tốt cho tôi" - rất tiếc khi nghe điều đó về bạn, bởi vì đó là những gì goto casedành cho. Lợi thế của nó so với dự đoán là nó rõ ràng. Rằng một số người ở đây phản đối goto casechỉ cho thấy rằng họ đã được truyền bá chống lại "goto" mà không có bất kỳ hiểu biết nào về vấn đề này và không thể tự mình suy nghĩ. Khi Dijkstra viết "GOTO được coi là có hại", anh ấy đã giải quyết các ngôn ngữ không có bất kỳ phương tiện nào khác để thay đổi dòng kiểm soát.
Jim Balter

@JimBalter và sau đó có bao nhiêu người trích dẫn Dijkstra về điều đó sẽ trích dẫn Knuth rằng "tối ưu hóa sớm là gốc rễ của mọi tội lỗi" mặc dù câu nói đó là khi Knuth viết rõ ràng về việc gotocó thể hữu ích như thế nào khi tối ưu hóa mã?
Jon Hanna

1

Bạn có thể đạt được thông qua like c ++ bằng từ khóa goto.

VÍ DỤ:

switch(num)
{
   case 1:
      goto case 3;
   case 2:
      goto case 3;
   case 3:
      //do something
      break;
   case 4:
      //do something else
      break;
   case default:
      break;
}

9
Nếu chỉ có ai đó đã đăng hai năm trước đó!

0

Một câu lệnh nhảy như ngắt được yêu cầu sau mỗi khối trường hợp, bao gồm cả khối cuối cùng cho dù đó là câu lệnh trường hợp hay câu lệnh mặc định. Với một ngoại lệ, (không giống như câu lệnh chuyển đổi C ++), C # không hỗ trợ sự rơi ngầm từ nhãn này sang nhãn khác. Một ngoại lệ là nếu một tuyên bố trường hợp không có mã.

- Tài liệu chuyển đổi C # ()


1
Tôi nhận ra hành vi này được ghi lại, tôi muốn biết TẠI SAO nó là như vậy, và bất kỳ sự thay thế nào để có được hành vi cũ.
Matthew Scharley

0

Sau mỗi câu lệnh case yêu cầu break hoặc goto statement ngay cả khi đó là trường hợp mặc định.


2
Nếu chỉ có ai đó đã đăng hai năm trước đó!

1
@Poldie thật buồn cười khi lần đầu tiên ... Shilpa bạn không cần nghỉ ngơi hoặc goto cho mọi trường hợp, chỉ cho mọi trường hợp với mã riêng của nó. Bạn có thể có nhiều trường hợp chia sẻ mã tốt.
Maverick

0

Chỉ cần một lưu ý nhanh để thêm rằng trình biên dịch cho Xamarin thực sự đã sai và nó cho phép chuyển đổi. Nó đã được sửa chữa, nhưng chưa được phát hành. Đã phát hiện ra điều này trong một số mã thực sự bị lỗi và trình biên dịch đã không phàn nàn.



-1

C # không hỗ trợ rơi vào các câu lệnh switch / case. Không chắc chắn tại sao, nhưng thực sự không có hỗ trợ cho nó. Liên kết


Điều đó là sai. Xem các câu trả lời khác ... hiệu quả của một sự sụp đổ ngầm có thể thu được bằng một cách rõ ràng goto case . Đây là một sự lựa chọn thiết kế có chủ ý, khôn ngoan của các nhà thiết kế C #.
Jim Balter

-11

Bạn đã quên thêm "break;" câu lệnh vào trường hợp 3. Trong trường hợp 2 bạn đã viết nó vào khối if. Vì vậy, hãy thử điều này:

case 3:            
{
    ans += string.Format("{0} hundred and ", numbers[number / 100]);
    break;
}


case 2:            
{
    int t = (number / 10) % 10;            
    if (t == 1)            
    {                
        ans += teens[number % 10];                
    }            
    else if (t > 1)                
    {
        ans += string.Format("{0}-", tens[t]);        
    }
    break;
}

case 1:            
{
    int o = number % 10;            
    ans += numbers[o];            
    break;        
}

default:            
{
    throw new ArgumentException("number");
}

2
Điều này tạo ra sản lượng sai rất lớn. Tôi để lại các báo cáo chuyển đổi theo thiết kế. Câu hỏi đặt ra là tại sao trình biên dịch C # coi đây là lỗi khi hầu như không có ngôn ngữ nào khác có hạn chế này.
Matthew Scharley

5
Thật là một thất bại tuyệt vời để hiểu. Và bạn đã có 5 năm để xóa cái này mà vẫn không làm như vậy? Tâm boggling.
Jim Balter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.