Tại sao bạn không sử dụng lệnh 'sử dụng' trong C #?


71

Các tiêu chuẩn mã hóa hiện có trong một dự án C # lớn bao gồm một quy tắc rằng tất cả các tên loại đều có đủ điều kiện, cấm sử dụng chỉ thị 'sử dụng'. Vì vậy, thay vì quen thuộc:

using System.Collections.Generic;

.... other stuff ....

List<string> myList = new List<string>();

(Có lẽ không có gì ngạc nhiên khi varcũng bị cấm.)

Tôi kết thúc với:

System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string>();

Đó là sự gia tăng 134% trong việc đánh máy, không có sự gia tăng nào cung cấp thông tin hữu ích. Theo quan điểm của tôi, 100% sự gia tăng là tiếng ồn (sự lộn xộn) thực sự cản trở sự hiểu biết.

Trong hơn 30 năm lập trình, tôi đã thấy một tiêu chuẩn như vậy được đề xuất một hoặc hai lần, nhưng chưa bao giờ được thực hiện. Lý do đằng sau nó thoát khỏi tôi. Người áp đặt tiêu chuẩn không phải là ngu ngốc, và tôi không nghĩ anh ta độc hại. Mà để lại nhầm lẫn là sự thay thế duy nhất trừ khi tôi thiếu một cái gì đó.

Bạn đã bao giờ nghe nói về một tiêu chuẩn như vậy được áp đặt? Nếu vậy, lý do đằng sau nó là gì? Bạn có thể nghĩ ra những lý lẽ khác ngoài "thật ngu ngốc" hay "mọi người khác sử dụng using" có thể thuyết phục người này gỡ bỏ lệnh cấm này không?

Lý luận

Những lý do cho sự cấm đoán này là:

  1. Thật khó khăn khi di chuột qua tên để có được loại đủ điều kiện. Tốt hơn là luôn luôn có loại đủ điều kiện hiển thị mọi lúc.
  2. Đoạn mã được gửi qua email không có tên đủ điều kiện và do đó có thể khó hiểu.
  3. Khi xem hoặc chỉnh sửa mã bên ngoài Visual Studio (chẳng hạn như Notepad ++), không thể có được tên loại đủ điều kiện.

Sự tranh cãi của tôi là cả ba trường hợp đều hiếm, và việc khiến mọi người phải trả giá bằng mã lộn xộn và khó hiểu chỉ để chứa một vài trường hợp hiếm hoi là sai lầm.

Các vấn đề xung đột không gian tên tiềm năng, mà tôi dự kiến ​​là mối quan tâm chính, thậm chí không được đề cập. Điều đó đặc biệt đáng ngạc nhiên bởi vì chúng tôi có một không gian tên MyCompany.MyProject.Core, đó là một ý tưởng đặc biệt tồi tệ. Tôi đã học được từ lâu rằng việc đặt tên bất cứ thứ gì Systemhoặc Coretrong C # là một con đường nhanh chóng dẫn đến sự điên rồ.

Như những người khác đã chỉ ra, xung đột không gian tên dễ dàng được xử lý bằng cách tái cấu trúc, bí danh không gian tên hoặc định tính một phần.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
maple_shaft

1
Một ví dụ trong thế giới thực về lý do tại sao nó có thể là một ý tưởng tốt (nhưng trong thế giới C ++): một câu trả lời cho Tại sao lại sử dụng không gian tên std; , gần "rằng cả hai" sử dụng "chỉ thị và tuyên bố đều bị cấm".
Peter Mortensen

Trước khi đọc phần Lý do, tôi đã đoán ra những lý do không thực tế vì công ty của tôi có các quy tắc tương tự.
Gqqnbig

Câu trả lời:


69

Câu hỏi rộng hơn:

Bạn đã bao giờ nghe nói về một tiêu chuẩn như vậy được áp đặt? Nếu vậy, lý do đằng sau nó là gì?

Có, tôi đã nghe nói về điều này và việc sử dụng tên đối tượng đủ điều kiện sẽ ngăn chặn xung đột tên. Mặc dù hiếm, nhưng khi chúng xảy ra, chúng có thể đặc biệt gai góc để tìm ra.


Một ví dụ: Loại kịch bản đó có thể được giải thích tốt hơn với một ví dụ.

Hãy nói rằng chúng tôi có hai Lists<T>thuộc hai dự án riêng biệt.

System.Collections.Generic.List<T>
MyCorp.CustomCollections.Optimized.List<T>

Khi chúng ta sử dụng tên đối tượng đủ điều kiện, rõ ràng là đối tượng List<T>đang được sử dụng. Sự rõ ràng đó rõ ràng phải trả giá bằng sự dài dòng.

Và bạn có thể tranh luận, "Đợi đã! Không ai sẽ sử dụng hai danh sách như thế!" Đó là nơi tôi sẽ chỉ ra kịch bản bảo trì.

Bạn đã viết mô-đun Foocho công ty của bạn sử dụng công ty được phê duyệt, tối ưu hóa List<T>.

using MyCorp.CustomCollections.Optimized;

public class Foo {
    List<object> myList = ...;
}

Sau đó, một nhà phát triển mới quyết định mở rộng công việc bạn đang làm. Không nhận thức được các tiêu chuẩn của công ty, họ cập nhật usingkhối:

using MyCorp.CustomCollections.Optimized;
using System.Collections.Generic;

Và bạn có thể thấy mọi thứ trở nên tồi tệ như thế nào một cách vội vàng.

Sẽ là tầm thường khi chỉ ra rằng bạn có thể có hai lớp độc quyền cùng tên nhưng trong các không gian tên khác nhau trong cùng một dự án. Vì vậy, nó không chỉ là mối quan tâm về việc va chạm với các lớp được cung cấp .NET framework.

MyCorp.WeightsAndLengths.Measurement();
MyCorp.TimeAndSpace.Measurement();

Thực tế:
Bây giờ, điều này có khả năng xảy ra trong hầu hết các dự án? Không thật sự lắm. Nhưng khi bạn đang làm việc trong một dự án lớn với nhiều đầu vào, bạn sẽ cố gắng hết sức để giảm thiểu khả năng mọi thứ bùng nổ trong bạn.

Các dự án lớn với nhiều nhóm đóng góp là một loại quái thú đặc biệt trong thế giới ứng dụng. Các quy tắc có vẻ không hợp lý cho các dự án khác trở nên phù hợp hơn do các luồng đầu vào cho dự án và khả năng những người đóng góp không đọc hướng dẫn của dự án.

Điều này cũng có thể xảy ra khi hai dự án lớn được hợp nhất với nhau. Nếu cả hai dự án có các lớp được đặt tên giống nhau, thì bạn sẽ thấy các xung đột khi bạn bắt đầu tham chiếu từ dự án này sang dự án khác. Và các dự án có thể quá lớn để tái cấu trúc hoặc ban quản lý sẽ không phê duyệt chi phí để tài trợ cho thời gian tái cấu trúc.


Lựa chọn thay thế:
Trong khi bạn không hỏi, thật đáng để chỉ ra rằng đây không phải là một giải pháp tuyệt vời cho vấn đề. Sẽ không phải là một ý tưởng tốt khi tạo các lớp sẽ va chạm mà không cần khai báo không gian tên của chúng.

List<T>, đặc biệt, nên được coi là một từ dành riêng và không được sử dụng làm tên cho các lớp học của bạn.

Tương tự, các không gian tên riêng lẻ trong dự án nên cố gắng có các tên lớp duy nhất. Phải thử và nhớ lại không gian tên Foo()mà bạn đang làm việc là vấn đề tinh thần tốt nhất nên tránh. Nói một cách khác: có MyCorp.Bar.Foo()MyCorp.Baz.Foo()sẽ làm vấp ngã các nhà phát triển của bạn và tốt nhất nên tránh.

Nếu không có gì khác, bạn có thể sử dụng không gian tên một phần để giải quyết sự mơ hồ. Ví dụ: nếu bạn hoàn toàn không thể đổi tên một trong hai Foo()lớp, bạn có thể sử dụng các không gian tên một phần của chúng:

Bar.Foo() 
Baz.Foo()

Lý do cụ thể cho dự án hiện tại của bạn:

Bạn đã cập nhật câu hỏi của mình với những lý do cụ thể mà bạn đã đưa ra cho dự án hiện tại của mình theo tiêu chuẩn đó. Chúng ta hãy nhìn vào chúng và thực sự lạc đề xuống con đường mòn thỏ.

Thật khó khăn khi di chuột qua tên để có được loại đủ điều kiện. Tốt hơn là luôn luôn có loại đủ điều kiện hiển thị mọi lúc.

"Cồng kềnh, cản trở, vướng víu?" À, không. Có lẽ gây phiền nhiễu. Di chuyển một vài ounce nhựa để thay đổi con trỏ trên màn hình không cồng kềnh . Nhưng tôi lạc đề.

Dòng lý luận này có vẻ giống như một sự che đậy hơn bất cứ điều gì khác. Chính thức, tôi đoán rằng các lớp trong ứng dụng được đặt tên yếu và bạn phải dựa vào không gian tên để thu thập lượng thông tin ngữ nghĩa phù hợp xung quanh tên lớp.

Đây không phải là một bằng chứng hợp lệ cho các tên lớp đủ điều kiện, có lẽ đó là một bằng chứng hợp lệ cho việc sử dụng các tên lớp đủ điều kiện một phần.

Đoạn mã được gửi qua email không có tên đủ điều kiện và do đó có thể khó hiểu.

Dòng lý luận này (tiếp tục?) Củng cố sự nghi ngờ của tôi rằng các lớp học hiện được đặt tên kém. Một lần nữa, có tên lớp kém không phải là lý do chính đáng để yêu cầu mọi thứ sử dụng tên lớp đủ điều kiện. Nếu tên lớp khó hiểu, có nhiều sai lầm hơn những gì tên lớp đủ điều kiện có thể sửa.

Khi xem hoặc chỉnh sửa mã bên ngoài Visual Studio (chẳng hạn như Notepad ++), không thể có được tên loại đủ điều kiện.

Trong tất cả các lý do, điều này gần như khiến tôi nhổ nước uống của tôi. Nhưng một lần nữa, tôi lạc đề.

Tôi đang tự hỏi tại sao nhóm thường xuyên chỉnh sửa hoặc xem mã bên ngoài Visual Studio? Và bây giờ chúng ta đang xem xét một sự biện minh rằng nó trực giao khá tốt với những gì không gian tên được cung cấp. Đây là một đối số được hỗ trợ công cụ trong khi không gian tên ở đó để cung cấp cấu trúc tổ chức cho mã.

Nghe có vẻ như dự án của riêng bạn chịu các quy ước đặt tên kém cùng với các nhà phát triển, những người không tận dụng những gì công cụ có thể cung cấp cho họ. Và thay vì giải quyết những vấn đề thực tế đó, họ đã cố gắng tát một người trợ giúp ban nhạc cho một trong những triệu chứng và đang yêu cầu tên lớp đủ điều kiện. Tôi nghĩ thật an toàn khi phân loại đây là một cách tiếp cận sai lầm.

Cho rằng có các lớp được đặt tên kém và giả sử bạn không thể cấu trúc lại, câu trả lời đúng là sử dụng Visual Studio IDE để tận dụng tối đa lợi thế của nó. Có thể xem xét thêm vào một plugin như gói VS PowerTools. Sau đó, khi tôi nhìn vào AtrociouslyNamedClass()tôi có thể nhấp vào tên lớp, nhấn F12 và được đưa thẳng đến định nghĩa của lớp để hiểu rõ hơn những gì nó đang cố gắng làm. Tương tự như vậy, tôi có thể nhấp Shift-F12 để tìm tất cả các điểm trong mã hiện đang phải sử dụng AtrociouslyNamedClass().

Liên quan đến các mối quan tâm công cụ bên ngoài - điều tốt nhất để làm là chỉ dừng lại. Đừng gửi email qua lại nếu họ không ngay lập tức xóa nội dung đề cập đến. Không sử dụng các công cụ khác bên ngoài Visual Studio vì các công cụ đó không có trí thông minh xung quanh mã mà nhóm của bạn cần. Notepad ++ là một công cụ tuyệt vời, nhưng nó không bị loại bỏ cho nhiệm vụ này.

Vì vậy, tôi đồng ý với đánh giá của bạn về ba biện minh cụ thể mà bạn đã được trình bày. Điều đó nói rằng, những gì tôi nghĩ rằng bạn đã nói là "Chúng tôi có những vấn đề tiềm ẩn trong dự án này mà không thể / không giải quyết và đây là cách chúng tôi 'sửa chữa' chúng." Và điều đó rõ ràng nói lên những vấn đề sâu sắc hơn trong đội có thể đóng vai trò là cờ đỏ cho bạn.


1
+1. Tôi cũng thực sự đã gặp một số va chạm khó chịu trong không gian tên nội bộ của chúng tôi. Cả trong việc chuyển mã kế thừa sang dự án "2.0" và chỉ với một vài tên lớp được chọn có giá trị ngữ nghĩa trong các bối cảnh không gian tên khác nhau. Điều thực sự khó khăn là hai thứ có cùng tên thường sẽ có giao diện tương tự nhau, vì vậy trình biên dịch sẽ không phàn nàn ... thời gian chạy của bạn sẽ!
Svidgen

23
Vấn đề này được giải quyết thông qua việc sử dụng các bí danh không gian tên, không phải bằng cách áp đặt các quy tắc ngớ ngẩn yêu cầu mã bằng cách lộn xộn với việc sử dụng không gian tên rõ ràng.
David Arno

4
@DavidArno - Tôi không đồng ý với bạn. Tuy nhiên, các dự án lớn có thể không có lựa chọn đó. Tôi chỉ đang chỉ ra lý do tại sao một dự án lớn có thể áp đặt quy tắc đó. Tôi không ủng hộ cho quy tắc, mặc dù. Chỉ là đôi khi nó được yêu cầu bởi vì nhóm không có bất kỳ lựa chọn nào khác.

4
@ GlenH7 bạn có thể muốn chỉ định các giải pháp khả dụng khác trong câu trả lời của mình. Tôi ghét nhìn thấy mọi người vấp phải điều này và nghĩ rằng "Ồ. Đó là một ý tưởng tuyệt vời!" +1 cho mục tiêu còn lại và thực dụng mặc dù.
RubberDuck

3
@JimMischel - Có vẻ như quy tắc này đang được sử dụng như một cái nạng cho một cái gì đó . Có thể không xác định được điều đó là gì. Ở cấp độ cao, vâng, đôi khi có lý do để không cho phép usingsnhưng có vẻ như dự án của bạn đủ điều kiện là một trong những trường hợp đó.

16

Tôi đã làm việc tại một công ty nơi họ có nhiều lớp có cùng tên, nhưng trong các thư viện lớp khác nhau.

Ví dụ,

  • Tên miền. Khách hàng
  • Di sản. Khách hàng
  • Dịch vụ khách hàng
  • ViewModel. Khách hàng
  • Cơ sở dữ liệu. Khách hàng

Thiết kế tồi, bạn có thể nói, nhưng bạn có biết những thứ này phát triển hữu cơ như thế nào và cái gì thay thế - đổi tên tất cả các lớp để bao gồm không gian tên? Tái cấu trúc chính của tất cả mọi thứ?

Trong mọi trường hợp, có một số nơi mà các dự án tham chiếu tất cả các thư viện khác nhau này cần để sử dụng nhiều phiên bản của lớp.

Với usingtrực tiếp ở trên đỉnh, đây là một nỗi đau lớn ở mông, ReSharper sẽ làm những điều kỳ quặc để thử và làm cho nó hoạt động, viết lại các usingchỉ thị một cách nhanh chóng, bạn sẽ có được Khách hàng không thể thực hiện được - Lỗi kiểu khách hàng và không biết loại nào là đúng.

Vì vậy, có ít nhất không gian tên một phần,

var cust = new Domain.Customer

hoặc là

public void Purchase(ViewModel.Customer customer)

cải thiện đáng kể khả năng đọc của mã và làm cho nó rõ ràng đối tượng bạn muốn.

Nó không phải là một tiêu chuẩn mã hóa, nó không phải là không gian tên đầy đủ và nó không được áp dụng cho tất cả các lớp như là tiêu chuẩn.


13
"cái gì thay thế, đổi tên tất cả các lớp để bao gồm không gian tên? tái cấu trúc chính của mọi thứ?" Vâng, đó là sự thay thế (chính xác).
David Arno

2
Chỉ trong ngắn hạn. Nó rẻ hơn nhiều so với việc sử dụng các không gian tên rõ ràng trong mã trong thời gian dài.
David Arno

3
Rất vui khi chấp nhận lập luận đó, miễn là bạn trả tiền cho tôi bằng tiền mặt chứ không phải cổ phiếu.
Ewan

8
@David: Không, nó KHÔNG phải là sự thay thế chính xác. Đủ điều kiện hoặc tất cả các mã định danh hoặc ít nhất là những cái thực sự va chạm là cách chính xác và lý do tại sao không gian tên tồn tại ở nơi đầu tiên là để cung cấp xung đột khi cùng tên được sử dụng trong các mô-đun khác nhau. Vấn đề là một số mô-đun có thể đến từ bên thứ 3, cơ sở mã mà bạn không thể sửa đổi. Vậy bạn sẽ làm gì, khi các số nhận dạng từ hai bên thứ ba khác nhau va chạm và bạn cần sử dụng cả hai thư viện, nhưng không thể cấu trúc lại một trong hai? Không gian tên tồn tại, bởi vì tái cấu trúc không phải lúc nào cũng có thể.
Kaiserludi

4
@CarlSixsmith, nếu một người đăng ký theo quan điểm của Martin Fowler về tái cấu trúc, thì nếu thay đổi đó tác động đến người dùng, thì bạn đã đúng, đó không phải là tái cấu trúc; đó là một hình thức tái cấu trúc khác. Điều này làm tăng hai điểm mặc dù: 1. tất cả các phương thức công khai có tự động là một phần của API không? 2. Bản thân Fowler thừa nhận rằng ông đang chiến đấu một trận thua theo định nghĩa này, với số lượng người ngày càng tăng sử dụng thuật ngữ "tái cấu trúc" để có nghĩa là tái cấu trúc tổng quát, bao gồm cả những thay đổi công khai.
David Arno

7

Không có gì là quá dài dòng hoặc quá ngắn: người ta nên tìm một trung gian vàng trong việc đủ chi tiết để ngăn chặn các lỗi tinh vi, trong khi tránh viết quá nhiều mã.

Trong C #, một ví dụ về đó là tên của các đối số. Tôi đã gặp nhiều lần một vấn đề trong đó tôi đã dành hàng giờ để tìm kiếm một giải pháp, trong khi phong cách viết dài dòng hơn có thể ngăn chặn lỗi ngay từ đầu. Vấn đề bao gồm một lỗi theo thứ tự của các đối số. Ví dụ, nó có đúng với bạn không?

if (...) throw new ArgumentNullException("name", "The name should be specified.");
if (...) throw new ArgumentException("name", "The name contains forbidden characters.");

Ngay từ cái nhìn đầu tiên, nó trông hoàn toàn ổn, nhưng có một lỗi. Chữ ký của các nhà xây dựng của ngoại lệ là:

public ArgumentException(string message, string paramName)
public ArgumentNullException(string paramName, string message)

Nhận thấy thứ tự lập luận?

Bằng cách áp dụng một kiểu dài hơn trong đó tên của một đối số được chỉ định mỗi khi phương thức chấp nhận hai hoặc nhiều đối số cùng loại , chúng tôi ngăn lỗi xảy ra lần nữa và vì vậy:

if (...) throw new ArgumentNullException(paramName: "name", message: "The name should be specified.");
if (...) throw new ArgumentException(paramName: "name", message: "The name contains forbidden characters.");

rõ ràng là lâu hơn để viết, nhưng kết quả là ít tốn thời gian hơn để gỡ lỗi.

Bị đẩy đến mức cực đoan, người ta có thể buộc phải sử dụng các đối số được đặt tên ở mọi nơi , kể cả trong các phương thức như doSomething(int, string)không có cách nào để trộn thứ tự của các tham số. Điều này có thể sẽ gây hại cho dự án trong thời gian dài, dẫn đến nhiều mã hơn mà không có lợi ích trong việc ngăn chặn lỗi tôi đã mô tả ở trên.

Trong trường hợp của bạn, động lực đằng sau “Không using” quy tắc là nó nên làm cho nó khó khăn hơn để sử dụng các loại sai, chẳng hạn như MyCompany.Something.List<T>vs System.Collections.Generic.List<T>.

Cá nhân, tôi sẽ tránh quy tắc như vậy bởi vì, IMHO, chi phí khó đọc mã cao hơn nhiều so với lợi ích của việc giảm nhẹ rủi ro sử dụng sai loại, nhưng ít nhất, có một lý do hợp lệ cho quy tắc này.


Các tình huống như thế này có thể được phát hiện bằng các công cụ. ReSharper đánh dấu paramNamebằng InvokerParameterNamethuộc tính và đưa ra cảnh báo nếu không có tham số như vậy tồn tại.
Johnbot

2
@ John John: họ chắc chắn có thể, nhưng trong một số trường hợp rất hạn chế. Nếu tôi có một SomeBusiness.Something.DoStuff(string name, string description)thì sao? Không có công cụ nào đủ thông minh để hiểu thế nào là tên và mô tả là gì.
Arseni Mourzenko

@ArseniMourzenko trong trường hợp này thậm chí con người cần phải mất thời gian để tìm hiểu xem lời mời có đúng hay không.
Gqqnbig

6

Không gian tên cho mã cấu trúc phân cấp, cho phép các tên ngắn hơn.

   MyCompany.Headquarters.Team.Leader
   MyCompany.Warehouse.Team.Leader

Nếu bạn cho phép từ khóa "sử dụng", có một chuỗi các sự kiện ...

  • Mọi người đều thực sự sử dụng một không gian tên toàn cầu
    (vì chúng bao gồm mọi không gian tên mà họ có thể muốn)
  • Mọi người bắt đầu đụng độ tên, hoặc
  • lo lắng về việc đụng độ tên.

Vì vậy, để tránh rủi ro, mọi người bắt đầu sử dụng tên thật dài:

   HeadquartersTeamLeader
   WarehouseTeamLeader

Tình hình leo thang ...

  • Một số người khác có thể đã chọn một tên, vì vậy bạn sử dụng tên dài hơn.
  • Tên càng ngày càng dài.
  • Độ dài có thể vượt quá 60 ký tự, không có tối đa - thật vô lý.

Tôi đã thấy điều này xảy ra, vì vậy có thể thông cảm với các công ty cấm "sử dụng".


11
Cấm usinglà lựa chọn hạt nhân. Bí danh không gian tên và trình độ một phần được ưa thích hơn.
Jim Mischel

1

Vấn đề với usinglà nó kỳ diệu thêm vào không gian tên mà không cần khai báo rõ ràng. Đây là một vấn đề lớn hơn đối với các lập trình viên bảo trì gặp phải một cái gì đó giống List<>và không quen thuộc với tên miền, không biết usingmệnh đề nào đã giới thiệu nó.

Một vấn đề tương tự xảy ra trong Java nếu người ta viết import Java.util.*;chứ không phải import Java.util.List;ví dụ; khai báo sau chứng minh tên đã được giới thiệu để khi List<>xuất hiện sau trong nguồn, nguồn gốc của nó được biết đến từ importkhai báo.


6
Trong khi sự thật là ai đó không quen thuộc với tên miền sẽ gặp một số khó khăn, tất cả những gì anh ta phải làm là di chuột qua tên loại và anh ta sẽ có được tên đủ điều kiện. Hoặc anh ta có thể nhấp chuột phải và đi thẳng đến định nghĩa loại. Đối với các loại .NET Framework, có lẽ anh ta đã biết mọi thứ ở đâu. Đối với các loại tên miền cụ thể, có lẽ anh ta sẽ mất một tuần để trở nên thoải mái. Tại thời điểm đó, các tên đủ điều kiện chỉ là tiếng ồn cản trở sự hiểu biết.
Jim Mischel

Jim .. Tôi vừa thử di chuột qua một định nghĩa và nó không hoạt động. Bạn đã xem xét khả năng một số lập trình viên trên thế giới không sử dụng Microsoft IDE chưa? Trong mọi trường hợp, bộ đếm của bạn không làm mất hiệu lực quan điểm của tôi, rằng nguồn sử dụng không còn là tài liệu tự động
Michael Montenero

2
Có, có những người làm việc trong C # đang tự làm khổ mình bằng cách không sử dụng các công cụ tốt nhất hiện có. Và, trong khi lập luận rằng trình độ chuyên môn đầy đủ là "tài liệu tự" có một số giá trị, mã như vậy có chi phí rất lớn về khả năng đọc. Tất cả các mã ngoại lai đó tạo ra nhiễu làm che khuất các phần của mã thực sự quan trọng.
Jim Mischel
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.