Một số lỗi thiết kế lớn nhất trong C # hoặc .NET Framework nói chung là gì?
Ví dụ: không có kiểu chuỗi không thể null và bạn phải kiểm tra DBNull khi tìm nạp các giá trị từ IDataReader.
Một số lỗi thiết kế lớn nhất trong C # hoặc .NET Framework nói chung là gì?
Ví dụ: không có kiểu chuỗi không thể null và bạn phải kiểm tra DBNull khi tìm nạp các giá trị từ IDataReader.
Câu trả lời:
Tôi hoàn toàn đồng ý với bài đăng này (đối với những người đang phân vân vì thiếu ToString, có một thuộc tính trình gỡ lỗi để cung cấp định dạng tùy chỉnh cho lớp của bạn).
Trên đầu danh sách trên, tôi cũng sẽ thêm các yêu cầu hợp lý sau:
T : new(string), hoặc ở đâuT : new(string, int)var e = new Foo(); e { Bar = baz };Either<T>" thì không, vì vậy tôi muốn có một số cách để khai báo một kiểu đại số đóng và thực thi đối sánh mẫu đầy đủ trên nó (về cơ bản hỗ trợ hạng nhất cho mẫu khách truy cập, nhưng hiệu quả hơn nhiều); vì vậy chỉ cần lấy enums, mở rộng chúng với hỗ trợ khớp mẫu đầy đủ và không cho phép các trường hợp không hợp lệ,System.IOlớp, giống như Stream, được thiết kế hơi kém; bất kỳ giao diện nào yêu cầu một số triển khai sẽ NotSupportedExceptionlà một thiết kế tồi,IListnên đơn giản hơn nhiều so với hiện tại; trên thực tế, điều này có thể đúng đối với nhiều các giao diện bộ sưu tập bê tông, như ICollection,INotifyPropertyChangedlấy tên trường dưới dạng một chuỗi; bạn có thể làm điều này bằng cách sử dụng một phương thức mở rộng nhận lambda với MemberExpression, tức là. () => Foo, nhưng điều đó không hiệu quả lắm,
nameof()toán tử cho các tên thành viên đơn lẻ, nhưng nó không hoạt động ở dạng chung ( nameof(T) == "T"thay vì tên của đối số kiểu thực tế: bạn vẫn cần làm typeof(T).Name)) - cũng như không cho phép bạn nhận chuỗi "đường dẫn" , ví dụ như nameof(this.ComplexProperty.Value) == "Value"hạn chế các ứng dụng có thể có của nó.IArithmetic ; các giao diện điều hành được chia sẻ hữu ích khác cũng có thể,readonlytừ khóa và C # 6.0 đã thêm thuộc tính tự động chỉ đọc, mặc dù nó không nghiêm ngặt như hỗ trợ ngôn ngữ thực cho các loại và giá trị bất biến.Bây giờ tôi cho là đủ rồi. Đây là tất cả những khó chịu mà tôi đã gặp phải trong tuần qua. Tôi có lẽ có thể tiếp tục hàng giờ đồng hồ nếu tôi thực sự dành tâm trí cho nó. C # 4.0 đã thêm các đối số được đặt tên, tùy chọn và mặc định, mà tôi thực sự chấp thuận.
Bây giờ cho một yêu cầu không hợp lý:
Đẹp không? :-)
List<T>một triệu Ts. Làm thế nào để bạn đề xuất rằng ảnh chụp nhanh được chụp một cách hiệu quả? # 21: Sử dụng readonlytừ khóa .... trong khi có một số gợi ý hay ở đây, chúng hầu như chỉ là - gợi ý, không phải lỗi thiết kế.
Reset()phương pháp trên IEnumerator<T>là một sai lầm (đối với khối iterator, spec ngôn ngữ thậm chí đòi hỏi rằng điều này ném một ngoại lệ)IEnumerable<out T>và Func<in T, out TResult>, nhưng không phải các kiểu cụ thể (như List<T>).ApplicationException khá thất vọng - đó có phải là một sai lầm?Containssau đó Add), vì vậy một bộ sưu tập đồng bộ hóa các hoạt động riêng biệt không phải là tất cả đều hữu ích
System.Collections.Concurrentloại , với TryAdd, GetOrAdd, TryRemove, vv đã được thêm vào trong .NET Framework 4.0 - mặc dù phương pháp mà chấp nhận một đại biểu nhà máy không đảm bảo nhà máy sẽ chỉ được gọi một lần cho mỗi khoá.using/ lockpattern - có lẽ cho phép chúng chia sẻ cú pháp có thể sử dụng lại (có thể mở rộng?); bạn có thể mô phỏng điều này bằng cách quay lại IDisposablevà sử dụng using, nhưng nó có thể rõ ràng hơnFoo(SqlConnection! connection)(chèn một dấu kiểm / throw) sẽ rất hay (trái ngược vớiint? v.v.)
dynamichoặc bạn có thể bật nó như thế nàyforeach mở rộng, có nghĩa là anon-method / lambdas nắm bắt biến duy nhất, thay vì một biến trên mỗi lần lặp (khó khăn với luồng / async / etc)
ApplicationExceptionlà một sai lầm - không hữu ích như họ hy vọng. Họ cũng nói rằng System.Exceptionlẽ ra phải như vậy abstract.
TextWriter là một cơ sở lớp của StreamWriter. wtf?
Điều đó luôn khiến tôi hoang mang đến tột cùng.
Một peev nhỏ C # pet - các hàm tạo sử dụng cú pháp C ++ / Java để hàm tạo trùng tên với lớp.
New() hoặc là ctor() sẽ đẹp hơn nhiều.
Và chắc chắn, các công cụ như coderush làm cho việc đổi tên các lớp ít gặp vấn đề hơn, nhưng từ một POV có thể đọc được, New () cung cấp sự rõ ràng tuyệt vời.
class Foo { new(int j) {i = j} int i; }
Newtừ khóa --uppercase là trái với quy ước), tôi ngần ngại gọi nó là một lỗ hổng thiết kế. Họ muốn thu hút các nhà phát triển C ++ / Java hiện có, và việc vay mượn rất nhiều quy ước cú pháp cũ ngu ngốc được cho là đã giúp họ đạt được mục tiêu.
Tôi không hiểu rằng bạn không thể làm
trong đó T: mới (U)
Vì vậy, bạn khai báo rằng kiểu chung T có một phương thức khởi tạo không mặc định.
biên tập:
Tôi muốn làm điều này:
public class A
{
public A(string text)
{
}
}
public class Gen<T> where T : new(string text)
{
}
Tôi thực sự ngạc nhiên khi tôi là người đầu tiên đề cập đến vấn đề này:
Tập dữ liệu được nhập ADO.NET không hiển thị các cột có thể làm trống dưới dạng thuộc tính của các kiểu có thể vô hiệu. Bạn sẽ có thể viết điều này:
int? i = myRec.Field;
myRec.Field = null;
Thay vào đó, bạn phải viết điều này, điều này thật ngu ngốc:
int? i = (int?)myRec.IsFieldNull() ? (int?)null : myRec.Field;
myRec.SetFieldNull();
Điều này đã gây khó chịu trong .NET 2.0 và thậm chí còn khó chịu hơn khi bạn phải sử dụng jiggery-pokery như trên trong các truy vấn LINQ gọn gàng đẹp mắt của mình.
Nó cũng gây khó chịu khi Add<TableName>Rowphương thức được tạo ra tương tự như không thể hiểu được với khái niệm về kiểu nullable. Hơn thế nữa kể từ khi tạoTableAdapter phương thức không phải như vậy.
Không có nhiều thứ trong .NET khiến tôi cảm thấy như nhóm nhà phát triển đã nói "Được rồi, các chàng trai, chúng ta đủ gần rồi - hãy giao hàng đi!" Nhưng điều này chắc chắn có.
DBNull.Value, khi nullbản thân nó đã hoàn toàn đủ để đại diện cho NULL. May mắn thay, LINQ-to-SQL chỉ sử dụng null cho NULL.
Chỉnh sửa
5. Một điều khó chịu khác của tôi là cách System.Reflection.BindingFlags, có các cách sử dụng khác nhau tùy thuộc vào phương pháp bạn sử dụng. Ví dụ trong FindField, CreateInstance hoặc SetField nghĩa là gì? Đây là một trường hợp mà họ đã quá tải ý nghĩa đằng sau cách liệt kê này gây nhầm lẫn.
Tôi không biết rằng tôi muốn nói rằng đó là một lỗi thiết kế, nhưng sẽ thực sự tuyệt vời nếu bạn có thể suy ra một biểu thức lambda theo cách giống như bạn có thể làm trong VB:
VB:
Dim a = Function(x) x * (x - 1)
C #
Thật tuyệt nếu có thể làm được điều này:
var a = x => x * (x - 1);
Thay vì phải làm điều này:
Func<int, int> a = x => x * (x - 1);
Tôi nhận ra không còn bao lâu nữa, nhưng trong Code Golf mọi nhân vật đều được tính là chết tiệt! Họ không tính đến điều đó khi thiết kế các ngôn ngữ lập trình này sao? :)
(int x) => x * (x -1);có thể có nghĩa Func<int, int>hoặc nó có thể có nghĩaExpression<Func<int, int>>
+không được định nghĩa cho object.
Lớp System.Object :
Equals và GetHashCode - không phải tất cả các lớp đều có thể so sánh được hoặc có thể băm, nên được chuyển sang một giao diện. IEquatable hoặc ICompABLE (hoặc tương tự) xuất hiện trong tâm trí.
ToString - không phải tất cả các lớp đều có thể được chuyển đổi thành chuỗi, nên được chuyển sang một giao diện. IFormattable (hoặc tương tự) xuất hiện trong tâm trí.
Các ICollection.SyncRoot bất động sản:
Generics đáng lẽ phải có ngay từ đầu:
EqualityComparer<T>.Defaultchính xác. Sau đó, cả hai var dict = new Dictionary<object, string>(EqualityComparer<object>.Default)và var dict = new Dictionary<object, string>()sẽ sử dụng tham chiếu so sánh / bình đẳng.
EqualityComparer<T>.Defaulthiện. Không cần phải kiểm tra mỗi lần tra cứu. Trình so sánh là một thuộc tính cho Dictionaryví dụ và mỗi người Dictionarybiết nó đang sử dụng thuộc tính nào.
Một trong những điều làm tôi khó chịu là Predicate<T> != Func<T, bool>nghịch lý. Cả hai đều thuộc loại đại biểu T -> boolnhưng chúng không tương thích với nhiệm vụ.
Một số người (ISV) muốn rằng bạn có thể biên dịch nó thành mã máy tại thời điểm xây dựng và liên kết nó, để tạo một tệp thực thi gốc không cần thời gian chạy dotNet.
Chúng tôi biết rất nhiều về các kỹ thuật OO phù hợp . Tách rời, lập trình theo hợp đồng, tránh kế thừa không đúng, sử dụng thích hợp các ngoại lệ, chính mở / đóng, khả năng thay thế Liskov, v.v. Tuy nhiên, các khung .Net không sử dụng các phương pháp hay nhất.
Đối với tôi, khuyết điểm lớn nhất trong thiết kế của .Net là không đứng trên vai của những người khổng lồ; quảng bá các mô hình lập trình ít hơn lý tưởng cho nhiều lập trình viên sử dụng khuôn khổ của họ .
Nếu MS chú ý đến điều này, thế giới kỹ thuật phần mềm có thể đã có những bước tiến nhảy vọt về chất lượng, độ ổn định và khả năng mở rộng trong thập kỷ này, nhưng than ôi, nó dường như đang thoái trào.
Tôi không thích câu lệnh switch C #.
Tôi muốn một cái gì đó như thế này
switch (a) {
1 : do_something;
2 : do_something_else;
3,4 : do_something_different;
else : do_something_weird;
}
Vì vậy, không còn dấu ngắt (dễ quên) và khả năng phân tách các giá trị khác nhau bằng dấu phẩy.
switchvề cơ bản bị hỏng trong tất cả các ngôn ngữ mô phỏng phiên bản cố ý làm tê liệt của C (được tối ưu hóa cho tốc độ!). VB có giá tốt hơn nhiều, nhưng vẫn chậm hơn nhiều năm so với các ngôn ngữ có khớp mẫu (Haskell, F #…).
Sự kiện trong C #, nơi bạn phải kiểm tra rõ ràng người nghe. Đó chẳng phải là điểm của các sự kiện, để phát sóng cho bất cứ ai tình cờ có mặt ở đó? Ngay cả khi không có bất kỳ?
Hành vi khủng khiếp (và khá vô hình đối với hầu hết mọi người) O (N ^ 2) của các trình lặp đệ quy / đệ quy lồng nhau .
Tôi khá buồn khi họ biết về nó, biết cách sửa chữa nó nhưng nó không được coi là có đủ ưu tiên để đưa vào danh sách.
Tôi luôn làm việc với các cấu trúc dạng cây và phải sửa lại mã của những người thông minh khi họ vô tình đưa ra các hoạt động đắt tiền theo cách này.
Cái hay của "gain foreach" là cú pháp đơn giản hơn, dễ dàng hơn khuyến khích mã chính xác, hiệu quả. Đây là "hố sâu thành công" mà tôi nghĩ họ nên khao khát trước khi thêm các tính năng mới cho thành công lâu dài của nền tảng.
Một số lớp triển khai giao diện nhưng chúng không triển khai nhiều phương thức của giao diện đó, ví dụ: Mảng thực hiện IList nhưng 4 trong số 9 phương thức ném NotSupportedException http://msdn.microsoft.com/en-us/library/system.array_members .aspx
Các thành viên tĩnh và các kiểu lồng nhau trong giao diện.
Điều này đặc biệt hữu ích khi một thành viên giao diện có một tham số thuộc loại cụ thể cho giao diện ( ví dụ: an enum). Sẽ rất tuyệt nếu lồng kiểu enum vào kiểu giao diện.
Tính chất mặc định nguy hiểm khủng khiếp của các sự kiện. Thực tế là bạn có thể gọi một sự kiện và ở trong trạng thái không nhất quán do người đăng ký bị xóa thật là kinh khủng. Xem các bài báo xuất sắc của Jon Skeet và Eric Lippert để đọc thêm về chủ đề này.
null mọi nơi.
const hư không.
Các API không nhất quán, ví dụ: thay đổi một mảng sẽ trả về voidnhưng thêm vào một StringBuffertrả về cùng một biến StringBuffer.
Giao diện bộ sưu tập không tương thích với cấu trúc dữ liệu bất biến, ví dụ: Addin System.Collections.Generic.IList<_>không thể trả về kết quả.
Không có cấu trúc gõ để bạn viết System.Windows.Media.Effects.SamplingMode.Bilinearthay vì chỉ Bilinear.
Có thể thay đổi IEnumeratorgiao diện được thực hiện bởi các lớp học khi nó phải là một bất biến struct.
Bình đẳng và so sánh là một mớ hỗn độn: bạn đã có System.IComparablevà Equalsnhưng sau đó bạn cũng đã có System.IComparable<_>, System.IEquatable, System.Collections.IComparer, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.Collections.Generic.IComparervà System.Collections.Generic.IEqualityComparer.
Tuples phải là cấu trúc nhưng cấu trúc ngăn cản việc loại bỏ lệnh gọi đuôi một cách không cần thiết, vì vậy một trong những kiểu dữ liệu cơ bản và phổ biến nhất sẽ phân bổ không cần thiết và phá hủy tính song song có thể mở rộng.
IEnumerator?
0 moonlighting as enum
đặc thù của enum: http://blogs.msdn.com/abhinaba/archive/2007/01/09/more-peculiarites-of-enum.aspx
như được minh họa bởi ví dụ điển hình này: http://plus.kaist.ac.kr/~shoh/postgresql/Npgsql/apidocs/Npgsql.NpgsqlParameterCollection.Add_overload_3.html
đề xuất của tôi, hãy đặt dấu "@" để sử dụng tốt:
thay vì:
if ((myVar & MyEnumName.ColorRed)! = 0)
dùng cái này:
if ((myVar & MyEnumName.ColorRed)! = @ 0)
Để thêm vào danh sách dài những điểm tốt của những người khác đã có:
DateTime.Now == DateTime.Now trong hầu hết, nhưng không phải tất cả các trường hợp.
Stringlà bất biến có một loạt các tùy chọn để xây dựng và thao tác, nhưng StringBuilder(có thể thay đổi) thì không.
Monitor.Entervà Monitor.Exitlẽ ra phải là các phương thức thể hiện, vì vậy thay vì tạo mới một đối tượng cụ thể để khóa, bạn có thể tạo mới a Monitorvà khóa đối tượng đó.
Trình hủy không bao giờ được đặt tên là trình hủy. Đặc tả ECMA gọi chúng là trình hoàn thiện, điều này ít gây nhầm lẫn hơn cho đám đông C ++, nhưng đặc tả ngôn ngữ vẫn gọi chúng là trình hủy.
DateTime.Nowmột là rõ ràng cuộc đua điều kiện nhất thế giới, nhưng 1 cho phần còn lại
Cách chúng tôi sử dụng các thuộc tính đôi khi làm tôi khó chịu. Tôi thích nghĩ chúng tương đương với các phương thức getFoo () và setFoo () của Java. Nhưng không phải vậy.
Nếu Nguyên tắc sử dụng thuộc tính nêu rõ rằng các thuộc tính có thể được đặt theo bất kỳ thứ tự nào để quá trình tuần tự hóa có thể hoạt động, thì chúng sẽ vô dụng đối với việc xác thực thời gian thiết lập. Nếu bạn đến từ một nền mà bạn muốn ngăn một đối tượng không cho phép chính nó rơi vào trạng thái không hợp lệ, thì thuộc tính không phải là giải pháp của bạn. Đôi khi tôi không thể thấy họ tốt hơn các thành viên công cộng như thế nào, vì chúng tôi rất hạn chế về những loại công việc mà chúng tôi phải làm trong tài sản.
Để đạt được điều đó, tôi đã luôn ước gì (điều này chủ yếu là suy nghĩ lung tung ở đây, tôi chỉ ước mình có thể làm được điều gì đó như thế này) rằng tôi có thể mở rộng cú pháp thuộc tính bằng cách nào đó. Hãy tưởng tượng một cái gì đó như thế này:
private string password;
public string Password
{
// Called when being set by a deserializer or a persistence
// framework
deserialize
{
// I could put some backward-compat hacks in here. Like
// weak passwords are grandfathered in without blowing up
this.password = value;
}
get
{
if (Thread.CurrentPrincipal.IsInRole("Administrator"))
{
return this.password;
}
else
{
throw new PermissionException();
}
}
set
{
if (MeetsPasswordRequirements(value))
{
throw new BlahException();
}
this.password = value;
}
serialize
{
return this.password;
}
}
Tôi không chắc liệu điều đó có hữu ích hay nó truy cập những thứ đó sẽ trông như thế nào. Nhưng tôi chỉ ước rằng tôi có thể làm được nhiều hơn với các thuộc tính và thực sự coi chúng như các phương thức get và set.
Các phương pháp mở rộng rất hay nhưng chúng là một cách xấu xí để giải quyết các vấn đề mà lẽ ra có thể được giải quyết sạch hơn với các mixin thực (hãy nhìn vào ruby để xem tôi đang nói gì), về chủ đề mixin. Một cách thực sự hay để thêm chúng vào ngôn ngữ là cho phép các generic được sử dụng để kế thừa. Điều này cho phép bạn mở rộng các lớp hiện có theo hướng đối tượng tốt:
public class MyMixin<T> : T
{
// etc...
}
điều này có thể được sử dụng như thế này để mở rộng một chuỗi, ví dụ:
var newMixin = new MyMixin<string>();
Nó mạnh hơn nhiều so với các phương thức mở rộng vì nó cho phép bạn ghi đè các phương thức, chẳng hạn như bọc chúng cho phép chức năng giống AOP bên trong ngôn ngữ.
Xin lỗi vì rant :-)
Microsoft sẽ không sửa các lỗi rõ ràng trong khuôn khổ và sẽ không cung cấp các móc để người dùng cuối có thể sửa chúng.
Ngoài ra, không có cách nào để thực thi .NET nhị phân vá lỗi trong thời gian chạy và không có cách nào để chỉ định phiên bản riêng của thư viện khung công tác .NET mà không có bản vá nhị phân các thư viện gốc (để chặn cuộc gọi tải) và ILDASM không thể phân phối lại nên tôi không thể tự động hóa bản vá.
Có thể gọi một phương thức mở rộng trên biến null được cho là có thể
đối tượng a = null; a.MyExtMethod (); // cái này có thể gọi được, giả sử ở đâu đó nó đã định nghĩa MyExtMethod
Nó có thể hữu ích nhưng nó không rõ ràng về các chủ đề ngoại lệ tham chiếu rỗng.
Một 'lỗ hổng' đặt tên. 'C' của "cấu hình" trong System.configuration.dll phải được viết hoa.
Xử lý ngoại lệ. Ngoại lệ nên được bắt hoặc ném ra giống như trong Java, trình biên dịch nên kiểm tra nó tại thời điểm biên dịch. Người dùng không nên dựa vào các nhận xét để biết thông tin ngoại lệ trong lời gọi đích.
Phương thức .Parameters.Add () trên SqlCommand trong V1 của khung công tác được thiết kế khủng khiếp - một trong những quá tải về cơ bản sẽ không hoạt động nếu bạn truyền vào một tham số có giá trị (int) bằng 0 - điều này dẫn đến việc chúng tạo ra phương thức .Parameters.AddWithValue () trên lớp SqlCommand.
ICollection<T>và IList<T>; tối thiểu, một giao diện thu thập hiệp biến chỉ đọc IListSource<out T>(với một điều tra viên, bộ lập chỉ mục và Bộ đếm) sẽ cực kỳ hữu ích.Transform(Sequence<T>, Func<T,T>) hàm cần xác định nhanh xem hàm trả về cùng một giá trị hay một giá trị khác. Nếu hàm không sửa đổi hầu hết / tất cả các đối số của nó, thì chuỗi đầu ra có thể chia sẻ một số / tất cả bộ nhớ từ chuỗi đầu vào. Nếu không có khả năng so sánh bitwise bất kỳ loại giá trị T nào, thì phải sử dụng phép so sánh chậm hơn nhiều, điều này làm ảnh hưởng rất nhiều đến hiệu suất.List<T>đến một giả định IListSource<U>(trong đó T: U) mặc dù lớp không thực thi giao diện đó một cách rõ ràng. Có ít nhất ba thư viện khác nhau (được viết độc lập) để cung cấp chức năng này (tất nhiên là có những hạn chế về hiệu suất - nếu có thể có một giải pháp hoàn hảo, sẽ không công bằng nếu gọi nó là một lỗ hổng trong .NET).WeakReference<T>(bạn có thể dễ dàng viết của riêng bạn, nhưng nó sẽ sử dụng phôi bên trong.)Predicate<T>vs Func<T,bool>). Tôi thường ước chúng ta có thể nhập cấu trúc cho các giao diện và đại biểu, để đạt được khớp nối lỏng lẻo hơn giữa các thành phần, bởi vì trong .NET, không đủ để các lớp trong các DLL độc lập triển khai cùng một giao diện - chúng cũng phải chia sẻ tham chiếu chung đến một phần ba DLL xác định giao diện.DBNull.Valuetồn tại mặc dù nullsẽ phục vụ cùng một mục đích tốt như nhau.variable = variable ?? value. Thật vậy, có một vài chỗ trong C # thiếu đối xứng. Ví dụ, bạn có thể viết if (x) y(); else z();(không có dấu ngoặc nhọn), nhưng bạn không thể viết try y(); finally z();.IList<T>, mặc dù tôi sẽ sử dụng IReadableByIndex<out T>và IAppendable<in T>. Tôi cũng đồng ý với nhiều thứ khác của bạn.
IListReader<T>;) - Tôi sử dụng từ "nguồn" làm từ trái nghĩa của "chìm" (một giao diện chỉ ghi).
IListSource<in T>hoặc IReadableList<out T>. Có thể có giá trị khi có các loại giao diện cơ sở bao gồm các phương thức không tồn tại trong tất cả các dẫn xuất, mặc dù tôi nghĩ rằng việc có các giao diện hơi chuyên biệt là điều tốt. Ví dụ, người ta có thể có một IList<T>phương thức chứa các phương thức thay đổi kích thước có thể hoạt động hoặc có thể không hoạt động và một IResizableList<T>phương thức triển khai các phương thức giống nhau, nhưng đảm bảo chúng sẽ hoạt động. Cách tiếp cận như vậy có thể hữu ích trong trường hợp một trường có thể giữ tham chiếu duy nhất còn tồn tại đến một danh sách có thể thay đổi hoặc một tham chiếu được chia sẻ đến một danh sách bất biến.
if (rl:(list as IResizableList<T>) != null) rl.Add(...);, nhưng có những đề xuất khác. Là tác giả của nhiều bộ sưu tập và bộ điều hợp bộ sưu tập khác nhau, điều khiến tôi khó chịu là viết rất nhiều phương pháp giả tạo ngoại lệ. Là một người hâm mộ loại an toàn, tôi không muốn được phép gọi các phương pháp bất hợp pháp. Một người hâm mộ IntelliSense, tôi không muốn thấy chúng được liệt kê.
Một điều khiến tôi ngạc nhiên trong 1.x là khi sử dụng System.Xml.XmlValidatingReader, ValidationEventHandler's ValidationEventArgskhông làm lộ ra phần bên dưới XmlSchemaException(được đánh dấu bên trong) có tất cả các thông tin hữu ích như linenumbervà position. Thay vào đó, bạn dự kiến sẽ phân tích cú pháp này ra khỏi thuộc tính Chuỗi tin nhắn hoặc sử dụng phản chiếu để tìm hiểu nó. Không tốt lắm khi bạn muốn trả lại một lỗi được làm sạch hơn cho người dùng cuối.
Không thích rằng bạn không thể sử dụng các giá trị của một enum này trong một enum khác, ví dụ:
enum Colors { white, blue, green, red, black, yellow }
enum SpecialColors { Colors.blue, Colors.red, Colors.Yellow }
typeof(Color)! = typeof(SpecialColors).
enum SpecialColors { blue = Colors.blue, red = Colors.red, yellow = Colors.Yellow }
Biến được nhập ngầm được triển khai IMO kém. Tôi biết bạn thực sự chỉ nên sử dụng chúng khi làm việc với các biểu thức Linq, nhưng thật khó chịu khi bạn không thể khai báo chúng bên ngoài phạm vi cục bộ.
Từ MSDN:
Lý do tôi nghĩ rằng đó là một triển khai kém là họ gọi nó là var, nhưng còn lâu mới trở thành một biến thể. Nó thực sự chỉ là cú pháp viết tắt để không phải nhập tên lớp đầy đủ (ngoại trừ khi được sử dụng với Linq)