แปลงระหว่าง List <T> และ IEnumerable <T> ได้อย่างอิสระ


103

ฉันสามารถแปลงList<MyObject>ไปยังIEnumerable<MyObject>และจากนั้นกลับมาอีกครั้ง?

ฉันต้องการทำสิ่งนี้เพื่อเรียกใช้ชุดคำสั่ง LINQ ในรายการเช่น Sort()


นี่คือคำถามที่ครอบคลุมในstackoverflow.com/questions/31708/…
John

คำตอบ:


148
List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myEnumerable.ToList();

30
อย่างไรก็ตามโปรดระวังว่า myEnumarable เป็นอินสแตนซ์อ็อบเจ็กต์เดียวกับ myList แต่ listAgain ไม่ใช่อินสแตนซ์อ็อบเจ็กต์เดียวกับ myEnumerable ขึ้นอยู่กับว่าคุณต้องการทำอะไรและ myEnumerable คืออะไร "List <string> listAgain = myEnumerable as List <string>;" อาจจะดีกว่า
ChrisW

1
Chrisw: โอ้ใช่คุณพูดถูก แต่อินเทอร์เฟซ <T> ของ IE ไม่สามารถเปลี่ยนรูปได้ดังนั้นจึงไม่ทำให้เกิดปัญหาในทิศทางนั้นและการส่งกลับจะรู้สึกสกปรกเมื่อคุณมีฟังก์ชั่นที่จะดูแลความปลอดภัยของประเภท
Tamas Czinege

1
คุณยังสามารถใช้วัตถุ myList ดั้งเดิมได้ (ผมคิดว่าผมไม่ได้รับจริงๆคำถาม)

6
เป็นเพียงว่าถ้าเขาแก้ไข myList เขาก็จะแก้ไข myEnumrable แต่ถ้าเขาแก้ไข listA อีกครั้งเขาก็จะไม่แก้ไข myEnumerable
ChrisW

15
อย่าลืมไม่งั้นusing System.Linq;จะไม่สามารถ ToList ()
Jason

21

A List<T>คือ an IEnumerable<T>จริงๆแล้วไม่จำเป็นต้อง 'แปลง' a List<T>เป็นIEnumerable<T>ไฟล์. เนื่องจาก a List<T>คือ an IEnumerable<T>คุณสามารถกำหนด a List<T>ให้กับตัวแปรประเภทIEnumerable<T>ได้

ในทางกลับกันไม่ใช่ว่าทุกคนIEnumerable<T>จะเป็นList<T>offcourse ดังนั้นคุณจะต้องเรียกToList()เมธอดสมาชิกของIEnumerable<T>.


4
ในทางเทคนิค ToList เป็นเมธอดสมาชิกของ System.Linq.Enumerable
Amy B

2
ฉันคิดว่าคุณสามารถส่ง IEnumerable ใน List ตามที่ David บอกได้
abatishchev

9

A List<T>อยู่แล้วIEnumerable<T>ดังนั้นคุณสามารถเรียกใช้คำสั่ง LINQ ได้โดยตรงบนList<T>ตัวแปรของคุณ

หากคุณไม่เห็นวิธีการขยาย LINQ อย่างที่OrderBy()ฉันคาดเดาว่าเป็นเพราะคุณไม่มีusing System.Linqคำสั่งในไฟล์ต้นฉบับของคุณ

คุณจำเป็นต้องแปลงผลลัพธ์นิพจน์ LINQ กลับเป็นList<T>อย่างชัดเจนแม้ว่า:

List<Customer> list = ...
list = list.OrderBy(customer => customer.Name).ToList()

"หากคุณไม่เห็นวิธีการขยาย LINQ เช่น OrderBy ()" นั่นคือปัญหาของฉันขอขอบคุณ
RyPope

5

นอกเหนือ: โปรดทราบว่าตัวดำเนินการ LINQ มาตรฐาน (ตามตัวอย่างก่อนหน้านี้) จะไม่เปลี่ยนแปลงรายการที่มีอยู่ - list.OrderBy(...).ToList()จะสร้างรายการใหม่ตามลำดับที่เรียงใหม่ อย่างไรก็ตามมันค่อนข้างง่ายในการสร้างวิธีการขยายที่ช่วยให้คุณใช้ lambdas กับList<T>.Sort:

static void Sort<TSource, TValue>(this List<TSource> list,
    Func<TSource, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    list.Sort((x,y) => comparer.Compare(selector(x), selector(y)));
}

static void SortDescending<TSource, TValue>(this List<TSource> list,
    Func<TSource, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    list.Sort((x,y) => comparer.Compare(selector(y), selector(x)));
}

จากนั้นคุณสามารถใช้:

list.Sort(x=>x.SomeProp); // etc

สิ่งนี้จะอัปเดตรายการที่มีอยู่ในลักษณะเดียวกับที่List<T>.Sortมักจะทำ


การแก้ไขคำสั่งนี้เล็กน้อย: ตัวดำเนินการ LINQ มาตรฐานจะไม่เปลี่ยนแปลงรายการที่มีอยู่ แต่พวกเขาสร้าง IEnumerable ใหม่ที่มีตรรกะที่จำเป็นสำหรับการทำงานของพวกเขาแทน อย่างไรก็ตามตรรกะนี้จะไม่ถูกดำเนินการจริงจนกว่าจะมีการร้องขอ IEnumerator
Vojislav Stojkovic

@Vojislav - ฉันมีความหมายในบริบทของตัวอย่างก่อนหน้านี้ที่ลงท้ายด้วยToList- ฉันจะชี้แจง
Marc Gravell

1

กำลังแปลงList<T>เป็นIEnumerable<T>

List<T>การดำเนินการIEnumerable<T>(และอื่น ๆ อีกมากมายเช่นIList<T>, ICollection<T>) ดังนั้นจึงไม่จำเป็นต้องแปลงรายการกลับเป็น IEnumerable เนื่องจากเป็นIEnumerable<T>ไฟล์.

ตัวอย่าง:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Person person1 = new Person() { Id = 1, Name = "Person 1" };
Person person2 = new Person() { Id = 2, Name = "Person 2" };
Person person3 = new Person() { Id = 3, Name = "Person 3" };

List<Person> people = new List<Person>() { person1, person2, person3 };

//Converting to an IEnumerable
IEnumerable<Person> IEnumerableList = people;

คุณยังสามารถใช้Enumerable.AsEnumerable()วิธีการ

IEnumerable<Person> iPersonList = people.AsEnumerable();

กำลังแปลงIEnumerable<T>เป็นList<T>

IEnumerable<Person> OriginallyIEnumerable = new List<Person>() { person1, person2 };
List<Person> convertToList = OriginallyIEnumerable.ToList();

นี้จะเป็นประโยชน์ในEntity Framework


0

เพื่อป้องกันการทำซ้ำในหน่วยความจำ resharper ขอแนะนำสิ่งนี้:

List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myList as List<string>() ?? myEnumerable.ToList();

.oList () ส่งคืนรายการที่ไม่เปลี่ยนรูปใหม่ ดังนั้นการเปลี่ยนแปลง listAgain จึงไม่มีผลกับ myList ในคำตอบของ @Tamas Czinege สิ่งนี้ถูกต้องในกรณีส่วนใหญ่ด้วยเหตุผลอย่างน้อยสองประการ: สิ่งนี้ช่วยป้องกันการเปลี่ยนแปลงในพื้นที่หนึ่งที่ส่งผลกระทบต่อพื้นที่อื่น ๆ (การมีเพศสัมพันธ์แบบหลวม) และสามารถอ่านได้มากเนื่องจากเราไม่ควรออกแบบโค้ดด้วยความกังวลเกี่ยวกับคอมไพเลอร์

แต่มีบางกรณีเช่นอยู่ในวง จำกัด หรือทำงานบนระบบหน่วยความจำฝังตัวหรือหน่วยความจำเหลือน้อยซึ่งควรคำนึงถึงคอมไพเลอร์ด้วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.