Khi nào nên sử dụng Cast () và Oftype () trong Linq


211

Tôi nhận thức được hai phương pháp đúc kiểu IEnumerabletừ một Arraylisttrong Linq và tự hỏi trong trường hợp nào sẽ sử dụng chúng?

ví dụ

IEnumerable<string> someCollection = arrayList.OfType<string>()

hoặc là

IEnumerable<string> someCollection = arrayList.Cast<string>()

Sự khác biệt giữa hai phương pháp này và tôi nên áp dụng từng trường hợp ở đâu?

Câu trả lời:


322

OfType- chỉ trả lại các phần tử có thể được chuyển một cách an toàn sang loại x.
Cast- sẽ cố gắng chuyển tất cả các thành phần thành loại x. nếu một số trong số họ không thuộc loại này, bạn sẽ nhận đượcInvalidCastException

EDIT
chẳng hạn:

object[] objs = new object[] { "12345", 12 };
objs.Cast<string>().ToArray(); //throws InvalidCastException
objs.OfType<string>().ToArray(); //return { "12345" }

1
Chúc mừng cho điều đó. Đã thử cả hai trước nhưng cả hai đều có các yếu tố thuộc loại dự kiến ​​do đó tôi không thể thấy sự khác biệt.

6
@SLaks chỉ ra một cách chính xác rằng bạn nên sử dụng Cast<T>khi bạn biết chắc rằng bộ sưu tập chỉ chứa Tcác phần tử loại . OfType<T>chậm hơn do iskiểm tra loại. Nếu bộ sưu tập là loại IEnumerable<T>,Cast<T> đơn giản sẽ chọn toàn bộ bộ sưu tập IEnumerable<T>và tránh liệt kê nó; OfType<T>vẫn sẽ liệt kê. ref: stackoverflow.com/questions/11430570/
Mạnh

23
Ngay cả trong trường hợp .Cast<string>()không ném khi liệt kê, nó cũng không tương đương .OfType<string>(). Lý do là nullcác giá trị luôn bị bỏ qua.OfType<TResult>() . Một ví dụ: new System.Collections.ArrayList { "abc", "def", null, "ghi", }.OfType<string>().Count()sẽ chỉ đưa ra 3; biểu thức tương tự với .Cast<string>()đánh giá 4.
Jeppe Stig Nielsen

1
nói cách khác, đó là một cái gì đó giống như sự khác biệt giữa các nhà khai thác 'như' và 'diễn viên'
faza

111

http://solutionizing.net/2009/01/18/linq-tip-enumerable-oftype/

Về cơ bản, Cast () được triển khai như thế này:

public IEnumerable<T> Cast<T>(this IEnumerable source)
{
  foreach(object o in source)
    yield return (T) o;
}

Việc sử dụng một biểu mẫu rõ ràng sẽ hoạt động tốt, nhưng sẽ dẫn đến một UnlimitedCastException nếu việc truyền không thành công. Một biến thể ít hiệu quả hơn nhưng hữu ích cho ý tưởng này là OfType ():

public IEnumerable<T> OfType<T>(this IEnumerable source)
{
  foreach(object o in source)
    if(o is T)
      yield return (T) o;
}

Phép liệt kê được trả về sẽ chỉ bao gồm các phần tử có thể được chuyển thành loại được chỉ định một cách an toàn.


38

Bạn nên gọi Cast<string>()nếu bạn biết rằng tất cả các mục là strings.
Nếu một số trong số chúng không có chuỗi, bạn sẽ có một ngoại lệ.

Bạn nên gọi OfType<string>()nếu bạn biết rằng một số mặt hàng không phải stringlà và bạn không muốn những mặt hàng đó.
Nếu một số trong số chúng không có chuỗi, chúng sẽ không có trong chuỗi mới IEnumerable<string>.


1
Câu trả lời này (hiện tại) là người duy nhất đưa ra lời khuyên rõ ràng khi sử dụng phương pháp nào.
CodeFox

4

Cần lưu ý rằng Cast(Of T)có thể được sử dụng trên IEnumerablekhông giống như các chức năng LINQ khác, vì vậy nếu có trường hợp bạn cần sử dụng LINQ trên một bộ sưu tập hoặc danh sách không chung chung như ArrayList, bạn có thể sử dụng Cast(Of T)để chuyển đến IEnumerable(Of T)nơi LINQ có thể hoạt động.


2

Cast()sẽ cố gắng truyền tất cả các phần tử của bộ sưu tập (và sẽ đưa ra một ngoại lệ nếu phần tử sai loại) trong khi OfType()sẽ chỉ trả về các phần tử thuộc loại thích hợp.


2

OfTypesẽ lọc các phần tử để chỉ trả về các phần tử của loại đã chỉ định. Castsẽ sụp đổ nếu một phần tử không thể được chuyển sang loại mục tiêu.


2

Cast<T>sẽ cố gắng đúc tất cả các mục theo loại đã cho T. Diễn viên này có thể thất bại hoặc ném một ngoại lệ. OfType<T>sẽ trả về một tập hợp con của bộ sưu tập gốc và chỉ trả về các đối tượng thuộc loại T.

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.