آموزش 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 تشکر