Danh sách <T> hoặc IList <T> [đã đóng]


495

Bất cứ ai có thể giải thích cho tôi tại sao tôi muốn sử dụng IList trên Danh sách trong C #?

Câu hỏi liên quan: Tại sao nó được coi là xấu để lộList<T>


1
tìm kiếm trên internet cho "mã đến một giao diện không phải là một triển khai" và bạn có thể đọc cả ngày..và tìm thấy một vài cuộc chiến h0ly.
granadaCoder

Câu trả lời:


446

Nếu bạn đang trưng bày lớp của mình thông qua một thư viện mà người khác sẽ sử dụng, bạn thường muốn phơi bày nó thông qua các giao diện hơn là các triển khai cụ thể. Điều này sẽ giúp nếu bạn quyết định thay đổi việc thực hiện lớp của mình sau này để sử dụng một lớp cụ thể khác. Trong trường hợp đó, người dùng thư viện của bạn sẽ không cần cập nhật mã của họ vì giao diện không thay đổi.

Nếu bạn chỉ sử dụng nó trong nội bộ, bạn có thể không quan tâm lắm, và sử dụng List<T>có thể ổn.


19
Tôi không hiểu sự khác biệt (tinh tế), có một số ví dụ bạn có thể chỉ cho tôi?
StingyJack

134
Giả sử ban đầu bạn đã sử dụng Danh sách <T> và muốn thay đổi để sử dụng CaseInsensitiveList <T> chuyên dụng, cả hai đều thực hiện IList <T>. Nếu bạn sử dụng loại cụ thể, tất cả các cuộc gọi cần phải được cập nhật. Nếu được hiển thị là IList <T>, người gọi sẽ không phải thay đổi.
tvanfosson

46
Ah. ĐỒNG Ý. Tôi hiểu rồi Chọn mẫu số chung thấp nhất cho hợp đồng. Cảm ơn!
StingyJack

16
Nguyên tắc này là một ví dụ về đóng gói, một trong ba trụ cột của lập trình hướng đối tượng. Ý tưởng là bạn ẩn các chi tiết triển khai khỏi người dùng và thay vào đó cung cấp cho họ một giao diện ổn định. Điều này là để giảm sự phụ thuộc vào các chi tiết có thể thay đổi trong tương lai.
jason

14
Cũng lưu ý rằng T []: IList <T>, vì lý do hiệu suất, bạn luôn có thể hoán đổi từ việc trả lại Danh sách <T> từ thủ tục của bạn sang trả lại T [] và nếu quy trình được tuyên bố sẽ trả lại IList <T> (hoặc có lẽ là ICollection <T> hoặc IEnumerable <T>) không có gì khác cần phải thay đổi.
yfeldblum

322

Câu trả lời ít phổ biến hơn là các lập trình viên muốn giả vờ phần mềm của họ sẽ được sử dụng lại trên toàn thế giới, khi mà phần lớn các dự án sẽ được duy trì bởi một số lượng nhỏ người và tuy nhiên các soundbites liên quan đến giao diện tốt, bạn đang ảo tưởng bản thân bạn.

Kiến trúc phi hành gia . Cơ hội bạn sẽ viết IList của riêng bạn để thêm bất cứ thứ gì vào những cái đã có trong .NET framework là rất xa đến nỗi các khối thạch lý thuyết dành riêng cho "các thực tiễn tốt nhất".

Phi hành gia phần mềm

Rõ ràng nếu bạn đang được hỏi bạn sử dụng gì trong một cuộc phỏng vấn, bạn nói IList, mỉm cười và cả hai đều hài lòng với chính mình vì quá thông minh. Hoặc cho một API đối mặt công khai, IList. Hy vọng bạn có được quan điểm của tôi.


65
Tôi phải không đồng ý với câu trả lời mỉa mai của bạn. Tôi không hoàn toàn không đồng ý với tình cảm của kiến ​​trúc quá mức là một vấn đề thực sự. Tuy nhiên tôi nghĩ rằng đặc biệt là trong trường hợp các bộ sưu tập có giao diện thực sự tỏa sáng. Giả sử tôi có một hàm trả về IEnumerable<string>, bên trong hàm tôi có thể sử dụng một List<string>cửa hàng sao lưu nội bộ để tạo bộ sưu tập của mình, nhưng tôi chỉ muốn người gọi liệt kê nội dung của nó, không thêm hoặc xóa. Việc chấp nhận một giao diện như một tham số truyền đạt một thông điệp tương tự "Tôi cần một bộ sưu tập các chuỗi, mặc dù vậy, đừng lo lắng, tôi sẽ không thay đổi nó."
joshperry

38
Phát triển phần mềm là tất cả về ý định dịch. Nếu bạn nghĩ rằng các giao diện chỉ hữu ích cho việc xây dựng các kiến ​​trúc quá khổ, hoành tráng và không có chỗ trong các cửa hàng nhỏ, thì tôi hy vọng rằng người ngồi đối diện với bạn trong cuộc phỏng vấn không phải là tôi.
joshperry

48
Ai đó đã phải nói Arec này ... ngay cả khi bạn đã có đủ loại mô hình học thuật theo đuổi thư ghét. +1 cho tất cả chúng ta, những người ghét nó khi một ứng dụng nhỏ được tải giao diện và nhấp vào "tìm định nghĩa" đưa chúng ta đến một nơi nào đó KHÁC hơn nguồn gốc của vấn đề ... Tôi có thể mượn cụm từ "Phi hành gia kiến ​​trúc" không? Tôi có thể thấy nó sẽ có ích.
Gats

6
Nếu có thể, tôi sẽ cho bạn 1000 điểm cho câu trả lời này. : D
Samuel

8
Tôi đã nói về kết quả rộng hơn của việc theo đuổi mô hình. Giao diện cho các giao diện phổ biến tốt, các lớp bổ sung để theo đuổi một mô hình, xấu.
Gats

186

Giao diện là một lời hứa (hoặc hợp đồng).

Vì nó luôn luôn với những lời hứa - càng nhỏ càng tốt .


56
Không phải lúc nào cũng tốt hơn, chỉ dễ dàng hơn để giữ! :)
Kirk Broadhurst

5
Tôi không nhận được điều này. Vì vậy, IListlà lời hứa. Đó là lời hứa nhỏ hơn và tốt hơn ở đây? Điều này không hợp lý.
nawfal

3
Đối với bất kỳ lớp học khác, tôi sẽ đồng ý. Nhưng không phải List<T>, vì AddRangekhông được xác định trên giao diện.
Jesse de Wit

3
Điều này không thực sự hữu ích trong trường hợp cụ thể này. Lời hứa tốt nhất là một trong đó được giữ. IList<T>hứa rằng nó không thể giữ được. Chẳng hạn, có một Addphương thức có thể ném nếu IList<T>tình cờ chỉ đọc. List<T>mặt khác luôn luôn có thể viết và do đó luôn giữ lời hứa. Ngoài ra, kể từ .NET 4.6, chúng tôi hiện có IReadOnlyCollection<T>IReadOnlyList<T>hầu như luôn phù hợp hơn IList<T>. Và họ là covariant. Tránh IList<T>!
ZunTzu

@ZunTzu Tôi cho rằng ai đó chuyển một bộ sưu tập bất biến như một người đột biến đã cố tình phá vỡ hợp đồng được trình bày - đó không phải là vấn đề với chính hợp đồng, ví dụ IList<T>. Ai đó cũng có thể thực hiện tốt IReadOnlyList<T>và làm cho mọi phương pháp cũng trở thành một ngoại lệ. Nó trái ngược với cách gõ vịt - bạn gọi nó là vịt, nhưng nó không thể quẫy như một con vịt. Đó là một phần của hợp đồng, ngay cả khi trình biên dịch không thể thực thi nó. Mặc dù vậy, tôi đồng ý 100% rằng IReadOnlyList<T>hoặc IReadOnlyCollection<T>nên được sử dụng để truy cập chỉ đọc.
Shelby Oldfield

93

Một số người nói "luôn luôn sử dụng IList<T>thay vì List<T>".
Họ muốn bạn thay đổi chữ ký phương thức của bạn từ void Foo(List<T> input)thànhvoid Foo(IList<T> input) .

Những người này là sai.

Nó nhiều sắc thái hơn thế. Nếu bạn đang trở lại mộtIList<T> phần của giao diện công cộng cho thư viện của mình, bạn sẽ để lại cho mình các tùy chọn thú vị để có thể tạo một danh sách tùy chỉnh trong tương lai. Bạn có thể không bao giờ cần tùy chọn đó, nhưng đó là một đối số. Tôi nghĩ đó là toàn bộ đối số để trả về giao diện thay vì loại cụ thể. Điều đáng nói, nhưng trong trường hợp này nó có một lỗ hổng nghiêm trọng.

Là một đối tượng nhỏ, bạn có thể thấy mỗi người gọi đều cần một List<T>mã và mã cuộc gọi bị lấp đầy.ToList()

Nhưng quan trọng hơn nhiều, nếu bạn chấp nhận IList như một tham số, bạn nên cẩn thận hơn, bởi vì IList<T>List<T>không hành xử theo cùng một cách. Mặc dù có sự giống nhau về tên và mặc dù chia sẻ một giao diện, họ không để lộ cùng một hợp đồng .

Giả sử bạn có phương pháp này:

public Foo(List<int> a)
{
    a.Add(someNumber);
}

Một đồng nghiệp hữu ích "tái cấu trúc" phương pháp để chấp nhận IList<int>.

Mã của bạn hiện đã bị hỏng, vì int[]thực hiện IList<int>, nhưng có kích thước cố định. Hợp đồng cho ICollection<T>(cơ sở IList<T>) yêu cầu mã sử dụng nó để kiểm tra IsReadOnlycờ trước khi cố gắng thêm hoặc xóa các mục khỏi bộ sưu tập. Hợp đồng List<T>không.

Nguyên tắc thay thế Liskov (đơn giản hóa) nói rằng một loại dẫn xuất sẽ có thể được sử dụng thay cho loại cơ sở, không có điều kiện tiên quyết hoặc hậu điều kiện bổ sung.

Điều này cảm thấy như nó phá vỡ nguyên tắc thay thế Liskov.

 int[] array = new[] {1, 2, 3};
 IList<int> ilist = array;

 ilist.Add(4); // throws System.NotSupportedException
 ilist.Insert(0, 0); // throws System.NotSupportedException
 ilist.Remove(3); // throws System.NotSupportedException
 ilist.RemoveAt(0); // throws System.NotSupportedException

Nhưng nó không. Câu trả lời cho điều này là ví dụ đã sử dụng IList <T> / ICollection <T> sai. Nếu bạn sử dụng ICollection <T>, bạn cần kiểm tra cờ IsReadOnly.

if (!ilist.IsReadOnly)
{
   ilist.Add(4);
   ilist.Insert(0, 0); 
   ilist.Remove(3);
   ilist.RemoveAt(0);
}
else
{
   // what were you planning to do if you were given a read only list anyway?
}

Nếu ai đó chuyển cho bạn một Mảng hoặc Danh sách, mã của bạn sẽ hoạt động tốt nếu bạn kiểm tra cờ mỗi lần và có dự phòng ... Nhưng thực sự; ai làm điều đó? Bạn không biết trước nếu phương pháp của bạn cần một danh sách có thể có thêm thành viên; bạn không xác định rằng trong chữ ký phương thức? Chính xác thì bạn sẽ làm gì nếu bạn được thông qua một danh sách chỉ đọc như thế int[]nào?

Bạn có thể thay thế một List<T>mã sử dụng IList<T>/ ICollection<T> chính xác . Bạn không thể đảm bảo rằng bạn có thể thay thế một IList<T>/ ICollection<T>thành mã sử dụngList<T> .

Có một sự hấp dẫn đối với Nguyên tắc phân chia trách nhiệm / nguyên tắc giao diện đơn trong rất nhiều đối số để sử dụng trừu tượng thay vì các loại cụ thể - phụ thuộc vào giao diện hẹp nhất có thể. Trong hầu hết các trường hợp, nếu bạn đang sử dụng a List<T>và bạn nghĩ rằng bạn có thể sử dụng giao diện hẹp hơn - tại sao không IEnumerable<T>? Điều này thường phù hợp hơn nếu bạn không cần thêm các mục. Nếu bạn cần thêm vào bộ sưu tập, hãy sử dụng loại bê tông List<T>,.

Đối với tôi IList<T>(và ICollection<T>) là phần tồi tệ nhất của .NET framework. IsReadOnlyvi phạm nguyên tắc ít bất ngờ nhất. Một lớp, chẳng hạn như Array, không bao giờ cho phép thêm, chèn hoặc xóa các mục không nên thực hiện giao diện với các phương thức Thêm, Chèn và Xóa. (xem thêm /software/306105/im THỰCing-an-interface-whoen-you-do-not-one-of-the -properies )

IList<T>một phù hợp tốt cho tổ chức của bạn? Nếu một đồng nghiệp yêu cầu bạn thay đổi chữ ký phương thức để sử dụng IList<T>thay vì List<T>, hãy hỏi họ cách họ thêm một yếu tố vào một IList<T>. Nếu họ không biết về IsReadOnly(và hầu hết mọi người không biết), thì đừng sử dụng IList<T>. Không bao giờ.


Lưu ý rằng cờ IsReadOnly xuất phát từ ICollection <T> và cho biết liệu các mục có thể được thêm hoặc xóa khỏi bộ sưu tập hay không; nhưng chỉ để thực sự nhầm lẫn mọi thứ, nó không cho biết liệu chúng có thể được thay thế hay không, trong trường hợp Mảng (trả lại IsReadOnlys == true).

Để biết thêm về IsReadOnly, hãy xem định nghĩa msd của ICollection <T> .IsReadOnly


5
Tuyệt vời, câu trả lời tuyệt vời. Tôi muốn thêm rằng, ngay cả khi IsReadOnlytruecho một IList, bạn vẫn có thể sửa đổi các thành viên hiện tại của nó! Có lẽ tài sản đó nên được đặt tên IsFixedSize?
xofz

(đã được thử nghiệm với việc vượt qua Arraynhư một IList, vì vậy đó là lý do tại sao tôi có thể sửa đổi các thành viên hiện tại)
xofz

1
@SamPearson có một thuộc tính IsFixedSize trên IList trong .NET 1, không bao gồm trong IList chung của .NET 2.0, nơi nó được hợp nhất với IsReadOnly, dẫn đến hành vi đáng ngạc nhiên xung quanh Mảng. Có một blog làm tan chảy não chi tiết về sự khác biệt tinh tế ở đây: enterpriseccraft
cầu toàn

7
Câu trả lời tuyệt vời! Ngoài ra, kể từ .NET 4.6, chúng tôi hiện có IReadOnlyCollection<T>IReadOnlyList<T>hầu như luôn phù hợp hơn IList<T>nhưng không có ngữ nghĩa lười biếng nguy hiểm IEnumerable<T>. Và họ là covariant. Tránh IList<T>!
ZunTzu

37

List<T>là một triển khai cụ thể IList<T>, là một thùng chứa có thể được xử lý giống như một mảng tuyến tính T[]sử dụng một chỉ số nguyên. Khi bạn chỉ định IList<T>làm kiểu đối số của phương thức, bạn chỉ xác định rằng bạn cần một số khả năng nhất định của vùng chứa.

Ví dụ, đặc tả giao diện không thực thi cấu trúc dữ liệu cụ thể được sử dụng. Việc thực hiện List<T>xảy ra với cùng một hiệu suất để truy cập, xóa và thêm các phần tử dưới dạng một mảng tuyến tính. Tuy nhiên, thay vào đó, bạn có thể tưởng tượng một triển khai được hỗ trợ bởi một danh sách được liên kết, trong đó việc thêm các phần tử vào cuối sẽ rẻ hơn (thời gian không đổi) nhưng truy cập ngẫu nhiên đắt hơn nhiều. (Lưu ý rằng .NET LinkedList<T>không không thực hiện IList<T>.)

Ví dụ này cũng cho bạn biết rằng có thể có các tình huống khi bạn cần chỉ định triển khai, không phải giao diện, trong danh sách đối số: Trong ví dụ này, bất cứ khi nào bạn yêu cầu một đặc tính hiệu suất truy cập cụ thể. Điều này thường được đảm bảo cho việc triển khai cụ thể của một container ( List<T>tài liệu: "Nó thực hiệnIList<T> giao diện chung sử dụng một mảng có kích thước được tăng động theo yêu cầu.").

Ngoài ra, bạn có thể muốn xem xét phơi bày chức năng tối thiểu bạn cần. Ví dụ. nếu bạn không cần thay đổi nội dung của danh sách, có lẽ bạn nên cân nhắc sử dụng IEnumerable<T>, phần IList<T>mở rộng.


Về tuyên bố cuối cùng của bạn về việc sử dụng IEnumerable thay vì IList. Điều này không phải lúc nào cũng được khuyến nghị, hãy lấy WPF làm ví dụ, nó sẽ chỉ tạo một đối tượng IList trình bao bọc để có tác động của perf - msdn.microsoft.com/en-us/l Library / bb613546.aspx
HAdes

1
Câu trả lời tuyệt vời, đảm bảo hiệu suất là thứ mà giao diện không thể cung cấp. Trong một số mã, điều này có thể khá quan trọng và sử dụng các lớp cụ thể truyền đạt ý định của bạn, nhu cầu của bạn đối với lớp cụ thể đó. Mặt khác, một giao diện cho biết "Tôi chỉ cần gọi bộ phương thức này, không có hợp đồng nào khác ngụ ý."
joshperry

1
@joshperry Nếu hiệu suất của một giao diện làm phiền bạn, bạn đã ở sai nền tảng ngay từ đầu. Impo, đây là microoptimization.
nawfal

@nawfal Tôi không bình luận về ưu / nhược điểm hiệu năng của giao diện. Tôi đã đồng ý và nhận xét về thực tế rằng khi bạn chọn đưa ra một lớp cụ thể làm đối số, bạn có thể truyền đạt ý định thực hiện. Lấy LinkedList<T>so với lấy List<T>so với IList<T>tất cả giao tiếp một cái gì đó của đảm bảo hiệu suất được yêu cầu bởi mã được gọi.
joshperry

28

Tôi sẽ chuyển câu hỏi xung quanh một chút, thay vì biện minh lý do tại sao bạn nên sử dụng giao diện trên triển khai cụ thể, hãy cố gắng giải thích lý do tại sao bạn sẽ sử dụng triển khai cụ thể thay vì giao diện. Nếu bạn không thể biện minh cho nó, hãy sử dụng giao diện.


1
Cách suy nghĩ rất thú vị về nó. Và một cách tốt để suy nghĩ khi lập trình - cảm ơn.
Đậu phộng

Nói hay lắm! Vì giao diện là cách tiếp cận linh hoạt hơn, bạn thực sự cần phải chứng minh những gì triển khai cụ thể đang mua cho bạn.
Nhà Cory

9
Cách suy nghĩ tuyệt vời. Tôi vẫn có thể trả lời: lý do của tôi được gọi là AddRange ()
PPC

4
lý do của tôi được gọi là Thêm (). đôi khi bạn muốn một danh sách mà bạn biết có thể lấy các yếu tố bổ sung, chắc chắn? Xem câu trả lời của tôi.
cầu toàn

19

IList <T> là một giao diện để bạn có thể kế thừa một lớp khác và vẫn triển khai IList <T> trong khi kế thừa Danh sách <T> ngăn bạn làm như vậy.

Ví dụ: nếu có một lớp A và lớp B của bạn kế thừa nó thì bạn không thể sử dụng Danh sách <T>

class A : B, IList<T> { ... }

15

Một nguyên tắc của TDD và OOP nói chung là lập trình cho một giao diện không phải là một triển khai.

Trong trường hợp cụ thể này vì về cơ bản bạn đang nói về một cấu trúc ngôn ngữ, không phải là một ngôn ngữ tùy chỉnh mà nó thường không thành vấn đề, nhưng nói ví dụ rằng bạn thấy Danh sách không hỗ trợ thứ bạn cần. Nếu bạn đã sử dụng IList trong phần còn lại của ứng dụng, bạn có thể mở rộng Danh sách với lớp tùy chỉnh của riêng mình và vẫn có thể vượt qua điều đó mà không cần cấu trúc lại.

Chi phí để làm điều này là tối thiểu, tại sao không tiết kiệm cho mình đau đầu sau này? Đó là những gì nguyên tắc giao diện là tất cả về.


3
Nếu ExtendedList <T> của bạn kế thừa Danh sách <T>, thì bạn vẫn có thể điều chỉnh nó trong hợp đồng Danh sách <T>. Đối số này chỉ hoạt động nếu bạn viết triển khai IList <T> của riêng bạn từ sratch (hoặc ít nhất là không kế thừa Danh sách <T>)
PPC

14
public void Foo(IList<Bar> list)
{
     // Do Something with the list here.
}

Trong trường hợp này, bạn có thể vượt qua trong bất kỳ lớp nào thực hiện giao diện IList <Bar>. Nếu bạn đã sử dụng Danh sách <Bar> thay vào đó, chỉ một thể hiện Danh sách <Bar> có thể được truyền vào.

Cách <Bar> của IList được ghép lỏng lẻo hơn so với cách Danh sách <Bar>.


13

Đáng ngạc nhiên là không có câu hỏi nào trong Danh sách này so với các câu hỏi (hoặc câu trả lời) của IList đề cập đến sự khác biệt về chữ ký. (Đó là lý do tại sao tôi tìm kiếm câu hỏi này trên SO!)

Vì vậy, đây là các phương thức có trong Danh sách không có trong IList, ít nhất là từ .NET 4.5 (khoảng năm 2015)

  • AddRange
  • Như đã đọc
  • Tìm kiếm nhị phân
  • Sức chứa
  • Convert ALL
  • Tồn tại
  • Tìm thấy
  • Tìm tất cả
  • Tìm chỉ số
  • Tìm kiếm nhanh
  • FindLast Index
  • Cho mỗi
  • GetRange
  • Chèn
  • Last IndexOf
  • Bỏ tất cả
  • Hủy bỏ thay đổi
  • Đảo ngược
  • Sắp xếp
  • ToArray
  • TrimExcess
  • TrueFor ALL

1
Không hoàn toàn đúng. ReverseToArraylà các phương thức mở rộng cho giao diện <T> của IE, mà IList <T> xuất phát từ đó.
Tarec

Đó là bởi vì những điều này chỉ có ý nghĩa trong Lists chứ không phải các triển khai khác IList.
HankCa

12

Trường hợp quan trọng nhất để sử dụng các giao diện trong quá trình triển khai là trong các tham số cho API của bạn. Nếu API của bạn có một tham số Danh sách, thì bất kỳ ai sử dụng nó đều phải sử dụng Danh sách. Nếu loại tham số là IList, thì người gọi có nhiều tự do hơn và có thể sử dụng các lớp bạn chưa từng nghe đến, thậm chí có thể không tồn tại khi mã của bạn được viết.


7

Điều gì nếu .NET 5.0 Thay thế System.Collections.Generic.List<T>cho System.Collection.Generics.LinearList<T>. .NET luôn sở hữu tên List<T>nhưng họ đảm bảo rằngIList<T> là hợp đồng. Vì vậy, IMHO chúng tôi (ít nhất là tôi) không được sử dụng tên của ai đó (mặc dù đó là .NET trong trường hợp này) và gặp rắc rối sau đó.

Trong trường hợp sử dụng IList<T>, người gọi luôn có những thứ cần thiết để làm việc và người thực hiện có thể tự do thay đổi bộ sưu tập cơ bản thành bất kỳ triển khai cụ thể thay thế nào củaIList


7

Tất cả các khái niệm về cơ bản được nêu trong hầu hết các câu trả lời ở trên về lý do tại sao sử dụng giao diện trên các triển khai cụ thể.

IList<T> defines those methods (not including extension methods)

IList<T> Liên kết MSDN

  1. Thêm vào
  2. Thông thoáng
  3. Chứa đựng
  4. Sao chép vào
  5. Nhận số
  6. Chỉ số
  7. Chèn
  8. Tẩy
  9. Hủy bỏ

List<T> thực hiện chín phương thức đó (không bao gồm các phương thức mở rộng), trên hết, nó có khoảng 41 phương thức công khai, cân nhắc trong việc xem xét sử dụng phương pháp nào trong ứng dụng của bạn.

List<T> Liên kết MSDN


4

Bạn sẽ bởi vì việc xác định IList hoặc ICollection sẽ mở ra cho các triển khai khác của giao diện của bạn.

Bạn có thể muốn có một IOrderRep repository xác định một tập hợp các đơn đặt hàng trong IList hoặc ICollection. Sau đó, bạn có thể có các loại triển khai khác nhau để cung cấp danh sách các đơn hàng miễn là chúng tuân thủ "quy tắc" được xác định bởi IList hoặc ICollection của bạn.


3

IList <> hầu như luôn luôn được ưu tiên theo lời khuyên của người đăng khác, tuy nhiên lưu ý rằng có một lỗi trong .NET 3.5 sp 1 khi chạy IList <> qua hơn một chu kỳ tuần tự hóa / giải tuần tự hóa với WCF DataContractSerializer.

Hiện tại đã có SP để sửa lỗi này: KB 971030


2

Giao diện đảm bảo rằng bạn ít nhất có được các phương thức bạn đang mong đợi ; nhận thức được định nghĩa của giao diện tức là. tất cả các phương thức trừu tượng sẽ được thực hiện bởi bất kỳ lớp nào kế thừa giao diện. Vì vậy, nếu ai đó tạo ra một lớp lớn của riêng mình bằng một số phương thức bên cạnh các phương thức mà anh ta thừa hưởng từ giao diện cho một số chức năng bổ sung và những phương thức này không hữu dụng với bạn, tốt hơn là sử dụng tham chiếu đến một lớp con (trong trường hợp này là giao diện) và gán đối tượng lớp cụ thể cho nó.

lợi thế bổ sung là mã của bạn an toàn trước mọi thay đổi đối với lớp cụ thể khi bạn đăng ký chỉ một vài phương thức của lớp cụ thể và đó là những phương thức sẽ có ở đó miễn là lớp cụ thể kế thừa từ giao diện bạn đang có sử dụng. Vì vậy, nó an toàn cho bạn và tự do cho lập trình viên đang viết triển khai cụ thể để thay đổi hoặc thêm nhiều chức năng hơn vào lớp cụ thể của mình.


2

Bạn có thể xem xét lập luận này từ nhiều góc độ, bao gồm một trong những cách tiếp cận OO hoàn toàn nói rằng lập trình chống lại Giao diện không phải là triển khai. Với suy nghĩ này, việc sử dụng IList tuân theo hiệu trưởng giống như chuyển qua và sử dụng Giao diện mà bạn xác định từ đầu. Tôi cũng tin vào các yếu tố khả năng mở rộng và linh hoạt được cung cấp bởi một Giao diện nói chung. Nếu một lớp thực hiện IList <T> cần được mở rộng hoặc thay đổi, mã tiêu thụ không phải thay đổi; nó biết những gì hợp đồng Giao diện IList tuân thủ. Tuy nhiên, bằng cách sử dụng một triển khai cụ thể và Danh sách <T> trên một lớp thay đổi, có thể khiến mã cuộc gọi cũng cần phải được thay đổi. Điều này là do một lớp tuân thủ IList <T> đảm bảo một hành vi nhất định không được đảm bảo bởi một loại cụ thể sử dụng Danh sách <T>.

Cũng có sức mạnh để làm điều gì đó như sửa đổi các cài đặt mặc định của List <T> trên một lớp thực hiện IList <T> cho nói .Add, lệnh .remove hoặc bất kỳ phương pháp IList khác cung cấp cho các nhà phát triển một rất nhiều tính linh hoạt và sức mạnh, nếu không xác định trước theo danh sách <T>


0

Thông thường, một cách tiếp cận tốt là sử dụng IList trong API đối mặt công khai của bạn (khi thích hợp và cần có ngữ nghĩa danh sách), sau đó Liệt kê nội bộ để triển khai API. Điều này cho phép bạn thay đổi thành một triển khai IList khác mà không vi phạm mã sử dụng lớp của bạn.

Danh sách tên lớp có thể được thay đổi trong khung .net tiếp theo nhưng giao diện sẽ không bao giờ thay đổi vì giao diện là hợp đồng.

Lưu ý rằng, nếu API của bạn sẽ chỉ được sử dụng trong các vòng lặp foreach, v.v., thì bạn có thể muốn xem xét chỉ hiển thị IEnumerable thay thế.

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.