آموزش LINQ
پنجشنبه 21 خرداد 1394LINQ تکنولوژی جدیدی است که شرکت ماکروسافت با عرضه نسخه ی سوم Net. آنرا معرفی نمود . هدف این مقاله ارائه برخی اصول درمورد LINQ می باشد .
هدف این مقاله ارائه برخی اصول درمورد LINQ برای برخی افراد که ممکن است هنوز درک درستی در این مورد به دست نیاورده اند ، می باشد . LINQ دسترسی اطلاعات و منابع داده را یکپارچه می کند و اجازه ترکیب اطلاعات ازمنابع مختلف با یکدیگر را می دهد . LINQ اختصار یافته Language Integrated Query می باشد . دستوراتی که LINQ برای پایگاه داده ارائه می دهد دقیقا مشابه دستورات SQL می باشد . Query ها را مستقیما در داخل زبان های برنامه نویسی NET. مانند #C و Visual Basic از طریق مجموعه از برنامه های افزودنی به این زبان ها یکپارچه می کند . قبل از LINQ ، توسعه دهندگان مجبور به استفاده از زبان های مختلفی مانند XML ، SQL یا XPath و فناوری های متفاوت و API هایی مانند ADO.NET یا XML در هر برنامه نوشته شده با استفاده از زبانی مانند #C یا VB.NET بودند.
یکی از جنبه های کلیدی LINQ این است که دربرابر هر نوع از اشیا یا منابع داده مورد استفاده قرار می گیرد و یک محیط برنامه نویسی سازگار فراهم می کند . نحوه و مفاهیم در تمامی موارد استفاده یکسان هستند :
زمانیکه نحوه استفاده از LINQ دربرابریک آرایه یا مجموعه را یاد می گیرید ، همچنین بسیاری از مفاهیم مورد نیاز برای استفاده از LINQ با یک پایگاه داده یا یک فایل XML را می دانید . یکی دیگر از جنبه های مهم LINQ این است که وقتی از آن استفاده می کنید، با یک نوع داده خاص کار می کنید . این کد پایه را بررسی کنید و لینک ها به منبع اطلاعات را ببینید :
using System; using System.Linq; public sealed class Program { static double Square(double n) { Console.WriteLine("Computing Square(" + n + ")..."); return Math.Pow(n, 2); } public static void Main() { int[] numbers = { 1, 2, 3 }; var query = from n in numbers select Square(n); foreach (var n in query) Console.WriteLine(n); } } OUTPUT: Computing Square(1)... 1 Computing Square(2)... 4 Computing Square(3)... 9
این کد یک متد بنام Square برای اعلام یک متغیر محلی implicitly-typed به منظور انجام عملیات بر آرایه یا دنباله از سه اعداد صحیح است . متد انتخابی توالی که در آن هر عنصر ورودی درlambda داده شده تبدیل شده است . تکرار هریک از اجزا را قادر می سازد که عملیات در هر اجزا انجام شود. در حقیقت،ایده کلی پشت یک شمارنده که تنها هدف از طریق پیشبرد و خواندن مطالب مجموعه دیگر است .شمارنده ها قابلیت نوشتن را فراهم نمی کنند . این نوع می تواند به عنوان مکان نما که پیشرفت های بیش از هر عنصر منحصر به فرد در مجموعه مشاهده شود،دریک زمان . IEnumerable نوع محتوایی که می توانند شمارش شوند را نشان می دهد ، در حالی که IEnumerable مسئول انجام شمارش واقعی است . پایه اصلی اطلاعات در تکنولوژی LINQ به ترتیب و عناصر آن است . دنباله هر شی که رابط IEnumerable و هر عنصر در هر مورد در دنباله پیاده سازی می کند . در اینجا به نمونه ای از کدهای پایه اشاره می کنیم :
using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { string[] names = { "Tom", "Mitch", "Steve" }; IEnumerable<string> filteredNames = System.Linq.Enumerable.Where (names, n => n.Length >= 4); foreach (string n in filteredNames) Console.Write(n + "|"); } } And here is the output: Mitch Steve
عبارات Lambda : عملگر های زنجیره ای Query
مثال قبلی تا حدی واقعی نبود به دلیل اینکه دو Query پایه lambda نشان داده بود ، هر یک شامل یک عملگر Query واحد می باشد .برای ساختن بیشتر Query های پیچیده ، از عملگرهای زنجیره ای بیشتری استفاده می شود :
using System; using System.Collections.Generic; using System.Collections; using System.Linq; public class Program { public static void Main() { string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" }; IEnumerable query = names .Where (n => n.Contains ("a")) .OrderBy (n => n.Length) .Select (n => n.ToUpper()); foreach (string name in query) Console.Write(name + "|"); } } // end of program // The same query constructed progressively: IEnumerable filtered = names.Where (n => n.Contains ("a")); IEnumerable sorted = filtered.OrderBy (n => n.Length); IEnumerable finalQuery = sorted.Select (n => n.ToUpper());
در اینجا Query پیچیده تری که با استفاده ازکلید واژه "var"از متغیر محلی implicitly استفاده میکند :
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; static class LanguageFeatures { class ProcessData { public Int32 Id { get; set; } public Int64 Memory { get; set; } public String Name { get; set; } } static void DisplayProcesses(Func<Process, Boolean> match) { // implicitly-typed local variables var processes = new List<ProcessData>(); foreach (var process in Process.GetProcesses()) { if (match(process)) { // object initializers processes.Add(new ProcessData { Id = process.Id, Name = process.ProcessName, Memory = process.WorkingSet64 }); } } // extension methods Console.WriteLine("Total memory: {0} MB", processes.TotalMemory() / 1024 / 1024); var top2Memory = processes .OrderByDescending(process => process.Memory) .Take(2) .Sum(process => process.Memory) / 1024 / 1024; Console.WriteLine( "Memory consumed by the two most hungry processes: {0} MB", top2Memory); // anonymous types var results = new { TotalMemory = processes.TotalMemory() / 1024 / 1024, Top2Memory = top2Memory, Processes = processes }; ObjectDumper.Write(results, 1); ObjectDumper.Write(processes); } static Int64 TotalMemory(this IEnumerable<ProcessData> processes) { Int64 result = 0; foreach (var process in processes) result += process.Memory; return result; } static void Main() { // lambda expressions DisplayProcesses(process => process.WorkingSet64 >= 20 * 1024 * 1024); } } If you examine this code, you will see that "ObjectDumper" is not defined, yet referred to. This means that we have a DLL reference file to compile as well: using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Reflection; public class ObjectDumper { public static void Write(object element) { Write(element, 0); } public static void Write(object element, int depth) { Write(element, depth, Console.Out); } public static void Write(object element, int depth, TextWriter log) { ObjectDumper dumper = new ObjectDumper(depth); dumper.writer = log; dumper.WriteObject(null, element); } TextWriter writer; int pos; int level; int depth; private ObjectDumper(int depth) { this.depth = depth; } private void Write(string s) { if (s != null) { writer.Write(s); pos += s.Length; } } private void WriteIndent() { for (int i = 0; i < level; i++) writer.Write(" "); } private void WriteLine() { writer.WriteLine(); pos = 0; } private void WriteTab() { Write(" "); while (pos % 8 != 0) Write(" "); } private void WriteObject(string prefix, object element) { if (element == null || element is ValueType || element is string) { WriteIndent(); Write(prefix); WriteValue(element); WriteLine(); } else { IEnumerable enumerableElement = element as IEnumerable; if (enumerableElement != null) { foreach (object item in enumerableElement) { if (item is IEnumerable && !(item is string)) { WriteIndent(); Write(prefix); Write("..."); WriteLine(); if (level < depth) { level++; WriteObject(prefix, item); level--; } } else { WriteObject(prefix, item); } } } else { MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance); WriteIndent(); Write(prefix); bool propWritten = false; foreach (MemberInfo m in members) { FieldInfo f = m as FieldInfo; PropertyInfo p = m as PropertyInfo; if (f != null || p != null) { if (propWritten) { WriteTab(); } else { propWritten = true; } Write(m.Name); Write("="); Type t = f != null ? f.FieldType : p.PropertyType; if (t.IsValueType || t == typeof(string)) { WriteValue(f != null ? f.GetValue(element) : p.GetValue(element, null)); } else { if (typeof(IEnumerable).IsAssignableFrom(t)) { Write("..."); } else { Write("{ }"); } } } } if (propWritten) WriteLine(); if (level < depth) { foreach (MemberInfo m in members) { FieldInfo f = m as FieldInfo; PropertyInfo p = m as PropertyInfo; if (f != null || p != null) { Type t = f != null ? f.FieldType : p.PropertyType; if (!(t.IsValueType || t == typeof(string))) { object value = f != null ? f.GetValue(element) : p.GetValue(element, null); if (value != null) { level++; WriteObject(m.Name + ": ", value); level--; } } } } } } } } private void WriteValue(object o) { if (o == null) { Write("null"); } else if (o is DateTime) { Write(((DateTime)o).ToShortDateString()); } else if (o is ValueType || o is string) { Write(o.ToString()); } else if (o is IEnumerable) { Write("..."); } else { Write("{ }"); } } }
حالا فایل ObjectDumper.cs را در DLL با استفاده از '/target:library'با رفتن به خط دستور کامپایل می کنیم،یا آن را بصورت فایل Class در VS Studio 2010 کامپایل می کنیم.توجه داشته باشید اگر از VS 2010 استفاده می کنید ،
به قسمت Project's properties بروید و اطمینان حاصل کنید که NET. Framework برابر با 4.0 می باشد . حالا فایل MyProgram.cs با مراجعه به ObjectDumper.dll: csc.exe /r:ObjectDumper.dll MyProgram.cs کامپایل می کنیم .
خروجی بصورت زیر می باشد :
C:\Windows\MICROS~1.NET\FRAMEW~1\V40~1.303>myprogram Total memory: 968 MB Memory consumed by the two most hungry processes: 314 MB TotalMemory=968 Top2Memory=314 Processes=... Processes: Id=3244 Memory=65527808 Name=sqlservr Processes: Id=5320 Memory=23556096 Name=sqlservr Processes: Id=3320 Memory=37498880 Name=DkService Processes: Id=952 Memory=47443968 Name=svchost Processes: Id=5272 Memory=167903232 Name=WINWORD Processes: Id=1108 Memory=68866048 Name=svchost Processes: Id=1096 Memory=90230784 Name=svchost Processes: Id=500 Memory=120848384 Name=AcroRd32 Processes: Id=2856 Memory=75415552 Name=explorer Processes: Id=1672 Memory=71299072 Name=digitaleditions Processes: Id=4348 Memory=162045952 Name=LINQPad Processes: Id=2576 Memory=35442688 Name=Babylon Processes: Id=2172 Memory=49131520 Name=SearchIndexer Id=3244 Memory=65527808 Name=sqlservr Id=5320 Memory=23556096 Name=sqlservr Id=3320 Memory=37498880 Name=DkService Id=952 Memory=47443968 Name=svchost Id=5272 Memory=167903232 Name=WINWORD Id=1108 Memory=68866048 Name=svchost Id=1096 Memory=90230784 Name=svchost Id=500 Memory=120848384 Name=AcroRd32 Id=2856 Memory=75415552 Name=explorer Id=1672 Memory=71299072 Name=digitaleditions Id=4348 Memory=162045952 Name=LINQPad Id=2576 Memory=35442688 Name=Babylon Id=2172 Memory=49131520 Name=SearchIndexer
لازم به ذکر است ،مواردی که در ادامه به آنها اشاره شده برای مدیریت کد های موجود در LINQ بکار می روند :
Implicitly typed local variables Object initializers Lambda expressions Extension methods Anonymous types
حالا این کد را مجددا بررسی می کنیم :
var processes = Process.GetProcesses() .Where(process => process.WorkingSet64 > 20 * 1024 * 1024) .OrderByDescending(process => process.WorkingSet64) .Select(process => new { process.Id, Name = process.ProcessName });
یک متغیر با استفده از کلمه کلیدی var در C# 3.0 اعلام می کنیم . این یک متغیر محلی implicitly typed می باشد. WorkingSet64 یک عبارت در lambda است . اکثر اپراتور های Query عبارت lambda را به عنوان استدلال بکار می برند . OrderByDescending و پارامتر های آن از extesion method هستند . کلمه کلیدی new از نوع ناشناخته (anonymous type) ، و Name از نوع object initializer می باشد .
- C#.net
- 3k بازدید
- 4 تشکر