ความแตกต่างระหว่าง IQueryable <T> และ IEnumerable <T> คืออะไร


คำตอบ:


258

แรกของทุกขยายอินเตอร์เฟซดังนั้นสิ่งที่คุณสามารถทำได้ด้วย "ธรรมดา" คุณยังสามารถทำอะไรกับIQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>เพียงแค่มีGetEnumerator()วิธีการที่ส่งกลับEnumerator<T>ที่คุณสามารถเรียกมันMoveNext()วิธีการย้ำถึงลำดับของT

อะไรIQueryable<T>ได้ว่าIEnumerable<T> ไม่เป็นสองคุณสมบัติโดยเฉพาะอย่างยิ่งหนึ่งที่ชี้ไปยังผู้ให้บริการแบบสอบถาม (เช่น LINQ เพื่อให้บริการ SQL) และชี้อีกครั้งเพื่อให้การแสดงออกแบบสอบถามที่เป็นตัวแทนของIQueryable<T>วัตถุเป็นรันไทม์ทะลุต้นไม้ไวยากรณ์นามธรรมที่สามารถ เข้าใจโดยผู้ให้บริการแบบสอบถามที่กำหนด (ส่วนใหญ่คุณไม่สามารถให้ LINQ กับนิพจน์ SQL แก่ผู้ให้บริการ LINQ to Entities ได้โดยไม่มีข้อยกเว้นเกิดขึ้น)

นิพจน์สามารถเป็นนิพจน์คงที่ของวัตถุเองหรือโครงสร้างที่ซับซ้อนมากขึ้นของชุดตัวดำเนินการแบบสอบถามและตัวถูกดำเนินการ ตัวให้บริการแบบสอบถามIQueryProvider.Execute()หรือIQueryProvider.CreateQuery()วิธีการที่เรียกว่ามีการแสดงออกผ่านไปแล้วผลIQueryableตอบแทนแบบสอบถามหรืออื่นจะถูกส่งกลับตามลำดับ


8
มีประโยชน์ในการใช้ AsQueryable หรือไม่?
Jordan

6
ประโยชน์เดียวคือความสะดวกสบาย AsQueryable()มันจะทำการส่ง enumerable ให้กับ queryable และคืนมันถ้ามันใช้IQueryableอินเตอร์เฟสหรือไม่ก็มันจะล้อมรอบด้วย a ConstantExpressionซึ่งถูกอ้างถึงในEnumerableQueryวัตถุที่ถูกส่งคืน
Mark Cidade


1
น่าอ่านบทความนี้
JenonD

ลิงค์ @JenonD ตายแล้วนี่คือวิธีการ backbackmachine: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/?hl=th
majjam

201

ข้อแตกต่างหลักคือตัวดำเนินการ LINQ สำหรับIQueryable<T>นำExpressionวัตถุแทนผู้รับมอบสิทธิ์ซึ่งหมายถึงตรรกะคิวรีแบบกำหนดเองที่ได้รับเช่นตัวเลือกเพรดิเคตหรือตัวเลือกค่าอยู่ในรูปแบบของแผนภูมินิพจน์แทนผู้แทนไปยังวิธีการ

  • IEnumerable<T> ดีมากสำหรับการทำงานกับลำดับที่ซ้ำในหน่วยความจำ แต่
  • IQueryable<T> ช่วยให้หน่วยความจำไม่เพียงพอเช่นแหล่งข้อมูลระยะไกลเช่นฐานข้อมูลหรือบริการบนเว็บ

การดำเนินการค้นหา:

  • โดยที่การดำเนินการของแบบสอบถามจะถูกดำเนินการ"อยู่ระหว่างดำเนินการ"โดยทั่วไปสิ่งที่จำเป็นต้องมีคือรหัส (เป็นรหัส) เพื่อดำเนินการแต่ละส่วนของแบบสอบถาม

  • ในกรณีที่การดำเนินการจะดำเนินการนอกกระบวนการตรรกะของแบบสอบถามจะต้องมีการแสดงในข้อมูลเช่นผู้ให้บริการ LINQ สามารถแปลงเป็นรูปแบบที่เหมาะสมสำหรับการดำเนินการออกจากหน่วยความจำ - ไม่ว่าจะเป็นแบบสอบถาม LDAP SQL หรืออะไรก็ตาม

เพิ่มเติมใน:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
ฉันชอบพูดถึงการดำเนินการออกจากหน่วยความจำ มันชี้แจงความแตกต่างในทางปฏิบัติจริงในการใช้งาน
Ishmael Smyrnow

2
แทนที่จะใช้ผู้รับมอบสิทธิ์เป็นพารามิเตอร์เช่น IEnumerable <T> ในกรณีที่วิธีการใด IQueryable <T> จะใช้พารามิเตอร์ Expression <TDelegate> เราไม่ได้ส่งรหัสไปยัง IQueryable <T> เรากำลังส่งต้นไม้แสดงออก (รหัสเป็นข้อมูล) สำหรับผู้ให้บริการ LINQ ในการวิเคราะห์ C # 3.0 และ LINQ
Lu55

มีบางอย่างเกิดขึ้นกับลิงก์รูปภาพของคุณ แต่ไม่ได้แสดงอยู่ในเนื้อหาโพสต์ด้วยเหตุผลบางประการcodeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey แต่ฉันเห็นภาพนั้นดีในคำตอบนี้: i.stack.imgur.com/2DAqv.jpg
VonC

190

นี่เป็นวิดีโอที่ดีใน youtubeซึ่งแสดงให้เห็นว่าอินเทอร์เฟซเหล่านี้แตกต่างกันอย่างไรน่าดู

ด้านล่างมีคำตอบยาว ๆ สำหรับคำอธิบาย

จุดสำคัญแรกที่ต้องจดจำคือIQueryableอินเทอร์เฟซที่สืบทอดมาจากIEnumerableดังนั้นสิ่งที่IEnumerableสามารถทำได้IQueryableสามารถทำได้

ป้อนคำอธิบายรูปภาพที่นี่

มีความแตกต่างมากมาย แต่ให้เราคุยกันเกี่ยวกับความแตกต่างที่ยิ่งใหญ่ซึ่งทำให้แตกต่างมากที่สุด IEnumerableอินเตอร์เฟสมีประโยชน์เมื่อโหลดคอลเล็กชันของคุณโดยใช้LINQหรือ Framework เอนทิตีและคุณต้องการใช้ตัวกรองกับคอลเลกชัน

พิจารณารหัสง่าย ๆ ด้านล่างซึ่งใช้IEnumerableกับกรอบงานเอนทิตี มันใช้Whereตัวกรองที่จะได้รับการบันทึกที่มีคือEmpId2

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

ที่นี่ตัวกรองจะถูกดำเนินการในฝั่งไคลเอ็นต์ที่เป็นIEnumerableรหัส ในคำอื่น ๆ ข้อมูลทั้งหมดจะถูกดึงข้อมูลจากฐานข้อมูลแล้วที่ลูกค้าสแกนและได้รับการบันทึกด้วยมีEmpId2

ป้อนคำอธิบายรูปภาพที่นี่

แต่ตอนนี้ดูโค้ดด้านล่างนี้เรามีการเปลี่ยนแปลงไปIEnumerable IQueryableมันสร้างแบบสอบถาม SQL ที่ฝั่งเซิร์ฟเวอร์และข้อมูลที่จำเป็นเท่านั้นที่ถูกส่งไปยังฝั่งไคลเอ็นต์

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นความแตกต่างระหว่างIQueryableและIEnumerableเป็นเรื่องเกี่ยวกับที่ดำเนินการตรรกะตัวกรอง หนึ่งรันบนฝั่งไคลเอ็นต์และอีกหนึ่งรันบนฐานข้อมูล

ดังนั้นหากคุณทำงานกับการเก็บรวบรวมข้อมูลในหน่วยความจำเท่านั้นIEnumerableเป็นตัวเลือกที่ดี แต่ถ้าคุณต้องการสืบค้นข้อมูลที่เชื่อมต่อกับฐานข้อมูล `` IQueryable เป็นตัวเลือกที่ดีกว่าเพราะช่วยลดปริมาณการใช้งานเครือข่ายและใช้ภาษา SQL


สวัสดีขอบคุณมากสำหรับคำอธิบายที่ยอดเยี่ยม ฉันเข้าใจว่าทำไม IQueryable จึงเป็นทางเลือกที่ดีกว่าสำหรับข้อมูล "หน่วยความจำไม่เพียงพอ" แต่ฉันพยายามที่จะเข้าใจว่าทำไม IEnumerable จึงดีกว่าสำหรับข้อมูล "ในหน่วยความจำ" ฉันยังคิดว่าการรับข้อมูลที่กรองดีกว่าการรับข้อมูลและใช้ตัวกรอง
Imad

เมื่อมันเป็น "ในหน่วยความจำ" มันไม่สำคัญ ข้อมูลอยู่ในหน่วยความจำแล้วในเวลาที่แน่นอนที่จะถูกกรองไม่สำคัญ
Roni Axelrad

@Imad ตัวอย่างเช่นการฉายข้อมูลโดยการแปลงเอนทิตี DateTimeOffset เป็น DateTime ไม่สามารถทำได้โดยใช้ IQueryable หรือด้วย EntityFunctions วิธีที่ดีที่สุดคือการ AsEnumerable () วัตถุเอนทิตีจากนั้นเลือก () ลงใน viewmodel ที่มี DateTime กระบวนการนี้ใช้ฟังก์ชั่นในหน่วยความจำ
Jeff Li

57

IEnumerable: IEnumerable เหมาะสมที่สุดสำหรับการทำงานกับการรวบรวมในหน่วยความจำ (หรือแบบสอบถามแบบโลคัล) IEnumerable ไม่ย้ายระหว่างรายการมันเป็นเพียงการรวบรวมเท่านั้น

IQueryable: เหมาะสมที่สุดกับ IQueryable สำหรับแหล่งข้อมูลระยะไกลเช่นฐานข้อมูลหรือบริการบนเว็บ (หรือข้อความค้นหาระยะไกล) IQueryable เป็นคุณสมบัติที่ทรงพลังมากที่ช่วยให้สถานการณ์การดำเนินการรอการตัดบัญชีที่น่าสนใจหลากหลาย (เช่นการสอบถามเพจและการเรียงตามองค์ประกอบ)

ดังนั้นเมื่อคุณต้องทำซ้ำผ่านคอลเลกชันในหน่วยความจำให้ใช้ IEnumerable หากคุณต้องการจัดการกับคอลเลกชันเช่นชุดข้อมูลและแหล่งข้อมูลอื่น ๆ ให้ใช้ IQueryable


3
IEnumerable ไม่ใช้การประมวลผลที่เลื่อนออกไปใช่หรือไม่
Ian Warburton

3
การประมวลผลที่เลื่อนออกไปนั้นมีทั้งใน IEnumerable และ IQueryable ข้อมูลที่น่าสนใจเพิ่มเติมสามารถดูได้ที่นี่: stackoverflow.com/questions/2876616/…
Ignacio Hagopian

18

ในคำง่าย ๆ ความแตกต่างที่สำคัญอื่น ๆ คือ IEnumerable เรียกใช้แบบสอบถามแบบใช้เลือกข้อมูลในฝั่งเซิร์ฟเวอร์โหลดข้อมูลในหน่วยความจำในฝั่งไคลเอ็นต์แล้วกรองข้อมูลในขณะที่ IQueryable เรียกใช้แบบสอบถามแบบใช้เลือกข้อมูลบนฝั่งเซิร์ฟเวอร์พร้อมตัวกรองทั้งหมด


17

ในชีวิตจริงถ้าคุณใช้ ORM เช่น LINQ-to-SQL

  • หากคุณสร้าง IQueryable ดังนั้นแบบสอบถามอาจถูกแปลงเป็น sql และเรียกใช้บนเซิร์ฟเวอร์ฐานข้อมูล
  • หากคุณสร้าง IEnumerable แล้วแถวทั้งหมดจะถูกดึงเข้าสู่หน่วยความจำในฐานะวัตถุก่อนเรียกใช้แบบสอบถาม

ในทั้งสองกรณีหากคุณไม่ได้โทรหา A ToList()หรือToArray()แบบสอบถามจะถูกดำเนินการทุกครั้งที่มีการใช้งานดังนั้นคุณจะต้องIQueryable<T>กรอกข้อมูลลงในกล่องรายการ 4 รายการจากนั้นแบบสอบถามจะทำงานกับฐานข้อมูล 4 ครั้ง

นอกจากนี้หากคุณขยายขอบเขตการค้นหาของคุณ:

q.Where(x.name = "a").ToList()

จากนั้นด้วย IQueryable SQL ที่สร้างขึ้นจะมี“ โดยที่ name =“ a” แต่ด้วย IEnumerable บทบาทอีกมากมายจะถูกดึงกลับมาจากฐานข้อมูลจากนั้นการตรวจสอบ x.name =“ a” จะดำเนินการโดย. NET


10

IEnumerable อ้างถึงคอลเล็กชัน แต่ IQueryable เป็นเพียงแบบสอบถามและจะถูกสร้างขึ้นภายใน Expression Tree เราจะเรียกใช้แบบสอบถามนี้เพื่อรับข้อมูลจากฐานข้อมูล


8

ด้านล่างทดสอบขนาดเล็กพูดถึงอาจจะช่วยให้คุณเข้าใจแง่มุมหนึ่งของความแตกต่างระหว่างและIQueryable<T> IEnumerable<T>ฉันทำซ้ำคำตอบนี้จากโพสต์นี้ที่ฉันพยายามเพิ่มการแก้ไขในโพสต์ของคนอื่น

ฉันสร้างโครงสร้างต่อไปนี้ใน DB (สคริปต์ DDL):

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

นี่คือสคริปต์แทรกเรคคอร์ด (สคริปต์ DML):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

ตอนนี้เป้าหมายของฉันคือการได้รับ 2 อันดับแรกจากEmployeeตารางในฐานข้อมูล ฉันเพิ่มรายการ ADO.NET Entity Data Model ลงในแอปพลิเคชันคอนโซลของฉันที่ชี้ไปที่Employeeตารางในฐานข้อมูลของฉันและเริ่มเขียนคำสั่ง LINQ

รหัสสำหรับเส้นทาง IQueryable :

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

เมื่อฉันเริ่มรันโปรแกรมนี้ฉันก็เริ่มเซสชันของตัวสร้างโปรไฟล์ SQL Query บนอินสแตนซ์ SQL Server ของฉันและนี่คือบทสรุปของการดำเนินการ:

  1. จำนวนข้อความค้นหาทั้งหมดที่เรียกใช้: 1
  2. ข้อความค้นหา: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

มันเป็นสิ่งที่IQueryableฉลาดพอที่จะใช้ส่วนTop (2)คำสั่งบนฝั่งเซิร์ฟเวอร์ฐานข้อมูลของตัวเองดังนั้นมันจึงนำระเบียน 2 จาก 5 เพียงสาย การกรองในหน่วยความจำเพิ่มเติมใด ๆ ไม่จำเป็นต้องใช้กับคอมพิวเตอร์ไคลเอนต์

รหัสสำหรับเส้นทาง IEnumerable :

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

บทสรุปของการดำเนินการในกรณีนี้:

  1. จำนวนข้อความค้นหาทั้งหมดที่เรียกใช้: 1
  2. ข้อความค้นหาที่บันทึกใน SQL profiler: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

ตอนนี้สิ่งที่IEnumerableนำระเบียนทั้ง 5 อยู่ในSalaryตารางแล้วทำการกรองในหน่วยความจำบนคอมพิวเตอร์ไคลเอนต์เพื่อรับระเบียน 2 อันดับแรก ดังนั้นข้อมูลเพิ่มเติม (3 บันทึกเพิ่มเติมในกรณีนี้) จึงถูกโอนผ่านสายโดยไม่จำเป็น


7

นี่คือสิ่งที่ฉันเขียนในโพสต์ที่คล้ายกัน (ในหัวข้อนี้) (และไม่ฉันมักจะไม่พูดเอง แต่บทความเหล่านี้เป็นบทความที่ดีมาก)

"บทความนี้จะเป็นประโยชน์: IQueryable VS IEnumerable ใน LINQ

การอ้างอิงบทความนั้น 'ตามเอกสาร MSDN การเรียกใช้งาน IQueryable จะดำเนินการโดยสร้างแผนผังนิพจน์ภายในแทน "วิธีการเหล่านี้ที่ขยาย IQueryable (Of T) ไม่ทำการสืบค้นใด ๆ โดยตรง แต่หน้าที่การใช้งานของพวกเขาคือการสร้างวัตถุ Expression ซึ่งเป็นทรีนิพจน์ที่แสดงถึงแบบสอบถามแบบสะสม" '

ต้นไม้ Expression เป็นโครงสร้างที่สำคัญมากใน C # และบนแพลตฟอร์ม. NET (สิ่งเหล่านี้มีความสำคัญโดยทั่วไป แต่ C # ทำให้มีประโยชน์มาก) เพื่อให้เข้าใจถึงความแตกต่างได้ดียิ่งขึ้นฉันขอแนะนำให้อ่านเกี่ยวกับความแตกต่างระหว่างนิพจน์และข้อความ ในข้อกำหนด C # 5.0 อย่างเป็นทางการที่นี่ สำหรับแนวคิดทางทฤษฎีขั้นสูงที่แยกเป็นแคลคูลัสแลมบ์ดานิพจน์ช่วยให้การสนับสนุนวิธีการเป็นวัตถุชั้นหนึ่ง ความแตกต่างระหว่าง IQueryable และ IEnumerable นั้นมีศูนย์กลางอยู่ที่จุดนี้ IQueryable สร้าง tree expression ในขณะที่ IEnumerable ไม่ได้อย่างน้อยก็ไม่ได้อยู่ในเงื่อนไขทั่วไปสำหรับพวกเราที่ไม่ทำงานในห้องปฏิบัติการลับของ Microsoft

นี่เป็นอีกบทความที่มีประโยชน์มากที่ให้รายละเอียดความแตกต่างจากมุมมองแบบพุชกับแบบดึง (โดย "push" กับ "pull" ฉันหมายถึงทิศทางของการไหลของข้อมูลเทคนิคการเขียนโปรแกรมแบบโต้ตอบสำหรับ. NET และ C #

นี่เป็นบทความที่ดีมากที่ให้รายละเอียดความแตกต่างระหว่างคำสั่ง lambdas และ lambdas การแสดงออกและกล่าวถึงแนวคิดของการแสดงออกของการแสดงออกในเชิงลึกยิ่งขึ้น: การเยี่ยมชมผู้แทน C #, ต้นไม้แสดงออกและการแสดงออก lambda ."


6

เราใช้IEnumerableและIQueryableจัดการข้อมูลที่ดึงมาจากฐานข้อมูล IQueryableสืบทอดมาจากIEnumerableดังนั้นจึงIQueryableมีIEnumerableคุณสมบัติทั้งหมด ข้อแตกต่างที่สำคัญระหว่างIQueryableและIEnumerableคือIQueryableเรียกใช้งานแบบสอบถามด้วยตัวกรองในขณะที่IEnumerableเรียกใช้แบบสอบถามก่อนแล้วจึงกรองข้อมูลตามเงื่อนไข

ค้นหาความแตกต่างของรายละเอียดเพิ่มเติมด้านล่าง:

IEnumerable

  1. IEnumerableมีอยู่ในSystem.Collectionsเนมสเปซ
  2. IEnumerable ดำเนินการแบบสอบถามแบบใช้เลือกข้อมูลในฝั่งเซิร์ฟเวอร์โหลดข้อมูลในหน่วยความจำบนฝั่งไคลเอ็นต์จากนั้นกรองข้อมูล
  3. IEnumerable เหมาะสำหรับการสืบค้นข้อมูลจากการรวบรวมในหน่วยความจำเช่น List, Array
  4. IEnumerable มีประโยชน์สำหรับ LINQ to Object และ LINQ to XML query

IQueryable

  1. IQueryableมีอยู่ในSystem.Linqเนมสเปซ
  2. IQueryable ดำเนินการ 'เลือกแบบสอบถาม' บนฝั่งเซิร์ฟเวอร์พร้อมตัวกรองทั้งหมด
  3. IQueryable เหมาะสำหรับการสืบค้นข้อมูลจากหน่วยความจำนอก (เช่นฐานข้อมูลระยะไกลบริการ)
  4. IQueryable มีประโยชน์สำหรับ LINQ กับการสืบค้น SQL

ดังนั้นIEnumerableโดยทั่วไปจะใช้สำหรับจัดการกับการรวบรวมในหน่วยความจำในขณะที่IQueryableโดยทั่วไปจะใช้เพื่อจัดการกับคอลเลกชัน


3

ทั้ง IEnumerable และ IQueryable นั้นใช้สำหรับเก็บข้อมูลและทำการดำเนินการจัดการข้อมูลเช่นการกรองในการรวบรวมข้อมูล ที่นี่คุณสามารถค้นหาความแตกต่างที่ดีที่สุดพร้อมตัวอย่าง http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html ป้อนคำอธิบายรูปภาพที่นี่


2

IQueryable เร็วกว่า IEnumerable ถ้าเราจัดการกับข้อมูลจำนวนมากจากฐานข้อมูลเพราะ IQueryable จะได้รับเฉพาะข้อมูลที่ต้องการจากฐานข้อมูลที่ IEnumerable ได้รับข้อมูลทั้งหมดโดยไม่คำนึงถึงความจำเป็นจากฐานข้อมูล


0

ienumerable: เมื่อเราต้องการจัดการกับหน่วยความจำ inprocess เช่นไม่มี dataconnection iqueryable: เมื่อต้องจัดการกับ sql server, เช่นการเชื่อมต่อ data ilist: การดำเนินการเพิ่มวัตถุลบวัตถุ ฯลฯ

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