Câu trả lời:
Nếu bạn có thể sử dụng LINQ, bạn có thể sử dụng:
var e = enumerable.First();
Điều này sẽ đưa ra một ngoại lệ mặc dù nếu liệt kê là trống: trong trường hợp đó bạn có thể sử dụng:
var e = enumerable.FirstOrDefault();
FirstOrDefault()
sẽ trả về default(T)
nếu liệt kê là trống, sẽ null
dành cho các loại tham chiếu hoặc 'giá trị không' mặc định cho các loại giá trị.
Nếu bạn không thể sử dụng LINQ, thì cách tiếp cận của bạn là đúng về mặt kỹ thuật và không khác gì tạo ra một điều tra viên bằng cách sử dụng các phương thức GetEnumerator
và MoveNext
để lấy kết quả đầu tiên (ví dụ này giả sử liệt kê là một IEnumerable<Elem>
):
Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
if (enumer.MoveNext()) e = enumer.Current;
}
Joel Coehoorn đã đề cập .Single()
trong các ý kiến; điều này cũng sẽ hoạt động, nếu bạn đang mong đợi vô số của mình chứa chính xác một yếu tố - tuy nhiên nó sẽ đưa ra một ngoại lệ nếu nó trống hoặc lớn hơn một yếu tố. Có một SingleOrDefault()
phương pháp tương ứng bao trùm kịch bản này theo cách tương tự FirstOrDefault()
. Tuy nhiên, David B giải thích rằng SingleOrDefault()
vẫn có thể đưa ra một ngoại lệ trong trường hợp vô số chứa nhiều hơn một mục.
Chỉnh sửa: Cảm ơn Marc Gravell đã chỉ ra rằng tôi cần loại bỏ IEnumerator
đối tượng của mình sau khi sử dụng nó - Tôi đã chỉnh sửa ví dụ không phải LINQ để hiển thị using
từ khóa để triển khai mẫu này.
Chỉ trong trường hợp bạn đang sử dụng .NET 2.0 và không có quyền truy cập vào LINQ:
static T First<T>(IEnumerable<T> items)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
iter.MoveNext();
return iter.Current;
}
}
Điều này sẽ làm những gì bạn đang tìm kiếm ... nó sử dụng thuốc generic để bạn có được mục đầu tiên trên bất kỳ loại IEnumerable nào.
Gọi nó như vậy:
List<string> items = new List<string>() { "A", "B", "C", "D", "E" };
string firstItem = First<string>(items);
Hoặc là
int[] items = new int[] { 1, 2, 3, 4, 5 };
int firstItem = First<int>(items);
Bạn có thể sửa đổi nó đủ dễ dàng để bắt chước phương thức mở rộng IEnumerable.EuityAt () của .NET 3.5:
static T ElementAt<T>(IEnumerable<T> items, int index)
{
using(IEnumerator<T> iter = items.GetEnumerator())
{
for (int i = 0; i <= index; i++, iter.MoveNext()) ;
return iter.Current;
}
}
Gọi nó như vậy:
int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);
Tất nhiên nếu bạn làm được tiếp cận với LINQ, sau đó có rất nhiều câu trả lời tốt posted đã ...
Chà, bạn đã không chỉ định phiên bản .Net nào bạn đang sử dụng.
Giả sử bạn có 3,5, một cách khác là phương thức ElementAt:
var e = enumerable.ElementAt(0);
Elem e = enumerable.FirstOrDefault();
//do something with e
Sử dụng FirstOrDefault hoặc vòng lặp foreach như đã đề cập. Nên tránh tìm nạp thủ công và gọi Hiện tại. foreach sẽ loại bỏ điều tra viên của bạn cho bạn nếu nó thực hiện IDis Dùng một lần. Khi gọi MoveNext và Hiện tại, bạn phải loại bỏ nó theo cách thủ công (nếu có thể áp dụng).
Nếu IEnumerable của bạn không phơi bày nó <T>
và Linq thất bại, bạn có thể viết một phương thức bằng cách sử dụng sự phản chiếu:
public static T GetEnumeratedItem<T>(Object items, int index) where T : class
{
T item = null;
if (items != null)
{
System.Reflection.MethodInfo mi = items.GetType()
.GetMethod("GetEnumerator");
if (mi != null)
{
object o = mi.Invoke(items, null);
if (o != null)
{
System.Reflection.MethodInfo mn = o.GetType()
.GetMethod("MoveNext");
if (mn != null)
{
object next = mn.Invoke(o, null);
while (next != null && next.ToString() == "True")
{
if (index < 1)
{
System.Reflection.PropertyInfo pi = o
.GetType().GetProperty("Current");
if (pi != null) item = pi
.GetValue(o, null) as T;
break;
}
index--;
}
}
}
}
}
return item;
}
bạn cũng có thể thử phiên bản chung hơn cung cấp cho bạn yếu tố thứ i
liệt kê.EuityAtOrDefault (i));
hy vọng nó giúp