اشتراکها
نگاهی به آینده #C و Visual Basic
مسیرراهها
ASP.NET Web API
- Best Practice هایی برای طراحی RESTful API - قسمت اول
- Best Practice هایی برای طراحی RESTful API - قسمت دوم
- ASP.NET Web API - قسمت اول
- ASP.NET Web API - قسمت دوم
- ASP.NET Web API - قسمت سوم
- ASP.NET Web API - قسمت چهارم
- ASP.NET Web API - قسمت پنجم
- بررسی مقدمات کتابخانهی JSON.NET
- تنظیمات و نکات کاربردی کتابخانهی JSON.NET
- LINQ to JSON به کمک JSON.NET
- تنظیمات JSON در ASP.NET Web API
- پیاده سازی یک MediaTypeFormatter برای پشتیبانی از MultiPart/form-data در Web API
- ارسال ویدیو بصورت Async توسط Web Api
- هاست سرویسهای Asp.Net Web Api با استفاده از OWIN و TopShelf
- افزودن خودکار کلاسهای WebAPI و SignalR Hub به برنامه در حالت SelfHost
- ساخت یک Web API که از عملیات CRUD پشتیبانی میکند
- فعالسازی استفاده از Session در ASP.NET MVC 4 API Controller ها
- واکشی اطلاعات سرویس Web API با استفاده از TypeScript و AngularJs
- استفاده از Web API در ASP.NET Web Forms
- ایجاد صفحات راهنما برای ASP.NET Web API
- محدود کردن درخواستهای Asp.Net Web Api بر اساس Client IP
اگر برنامه نویس NET. باشید، پس از مدتی کار با LINQ، در سایر زبانهای دیگر نیز به دنبال این قابلیت فوق العادهی functional یا تابعی خواهید گشت. در این مطلب، خلاصهای از متدهای توکار جاوا اسکریپت را که میتوانند معادلهایی برای متدهای LINQ to Objects دات نت باشند، بررسی خواهیم کرد.
تدارک ساختار ابتدایی این مطلب
در اینجا اینترفیسی را که بیانگر ساختار شیء شخص است، به صورت ذیل ایجاد میکنیم:
سپس آرایهای را بر اساس این شیء تدارک خواهیم دید:
در ادامه تمام اعمال مدنظر را بر روی این آرایه انجام میدهیم.
همچنین سه متد ذیل را نیز برای لاگ کردن عنوان آزمایش، نمایش محتوای آرایهی اصلی و نمایش نتیجهی آزمایش، به این کلاس اضافه میکنیم:
معادل متد Where در TypeScript
متد filter که جزو متدهای توکار ES5 است، میتواند معادلی برای متد Where، جهت فیلتر کردن عناصر بر اساس یک خاصیت، یا چندین خاصیت باشد:
با این خروجی
در اینجا نحوهی استفادهی از arrow functions ES6 را نیز جهت ساده سازی تعریف callback متد filter مشاهده میکنید که نمایش آن بسیار شبیه به عبارات LINQ در دات نت است.
معادل متد Any در TypeScript
متد some که جزو متدهای توکار ES5 است، میتواند معادلی برای متد Any باشد. اگر یکی از عناصر آرایه، بر اساس شرط تعیین شده یافت شود، این متد مقدار true را باز میگرداند:
با این خروجی:
در مثال اول، بررسی شدهاست که آیا شخصی با سن کمتر از 40 در این لیست وجود دارد؟
در مثال دوم، جستجویی بر روی تمام خواص شیء شخص انجام شدهاست. در اینجا توسط متد Object.keys، لیست خواص شیء یافت شدهاست. سپس بر روی این لیست توسط متد some، بررسی شدهاست که آیا خاصیت رشتهای وجود دارد که مساوی عبارت filterBy باشد؟ حاصل این بررسی به عنوان شرط متد filter جهت بازگشت آرایهی متناظری از اشخاص یافت شده، استفاده شدهاست.
معادل متد Contains در TypeScript
متد includes که جزو متدهای توکار ES7 است، میتواند معادلی برای متد Contains باشد و کار آن بررسی وجود عنصری در یک لیست است:
در اینجا باید دقت داشت که اگر آرایهی مدنظر رشتهای و یا عددی باشد، متد includes نتیجهی مطلوبی را بازگشت میدهد. اما چون در اینجا وجود یک شیء را در لیست اشخاص بررسی میکنیم، این مقایسه بر اساس ارجاع عناصر خواهد بود و نتیجهی نهایی یافت شدن آن، منفی است (شیء searchElement هیچ ارجاعی را در آرایهی اشخاص ندارد، هرچند ظاهر آن شبیه به یکی از عناصر آن است). حتی متد indexOf نیز به همین صورت عمل میکند.
یکی از روشهای مقایسهی بر اساس تمام مقادیر خواص یک شیء، استفاده از متد JSON.stringify است که اگر آنرا با متد some ترکیب کنیم، میتوان به نتیجهی مطلوبی رسید:
معادل متد All در TypeScript
متد every که جزو متدهای توکار ES5 است، میتواند معادلی برای متد All باشد و کار آن بررسی صحت شرط اعمالی، بر روی تک تک عناصر لیست است. اگر این بررسی با موفقیت صورت گرفت، مقدار true را بازگشت میدهد:
با این خروجی:
معادل متدهای First و FirstOrDefault در TypeScript
میتوان از متدهای filter و یا find بومی ES5 و ES 6 برای شبیه سازی متدهای First (یافتن اولین عنصر درخواستی در یک لیست) و FirstOrDefault استفاده کرد:
متد filter، در صورت برآورده نشدن شرط آن، یک آرایهی خالی را بازگشت میدهد که مقدار [0] آن، undefined است. بنابراین ترکیب آن با null ||، سبب بازگشت نال، در صورت خالی بودن آرایه میشود؛ یا همان حالت OrDefault (یا بازگشت مقدار پیش فرض، یا نال در اینجا). متد find نیز در صورت نیافتن عنصر درخواستی، مقدار undefined را بازگشت میدهد.
معادل متد FindIndex در TypeScript
متد findIndex که جزو متدهای توکار ES6 است، میتواند معادلی برای متد FindIndex در جهت یافتن ایندکس عنصری در یک لیست، بر اساس شرط درخواستی، باشد.
با این خروجی:
معادل متد Select در TypeScript
متد map که جزو متدهای توکار ES5 است، میتواند معادلی برای متد Select، برای تغییر شکل نهایی خروجی یک لیست باشد:
برای مثال در اینجا در لیست اشخاص، تنها خاصیت name آنها، انتخاب و بازگشت داده شدهاست:
معادل متد Aggregate در TypeScript
متد reduce که جزو متدهای توکار ES5 است، میتواند شبیه به متد Aggregate عمل کند و لیستی از عناصر را به یک مقدار کاهش دهد:
با این خروجی:
معادل متد ForEach در TypeScript
متد forEach که جزو متدهای توکار ES5 است، میتواند معادلی برای متد ForEach باشد که روشی functional برای پیمودن عناصر یک لیست است:
با این خروجی:
معادل متد OrderBy در TypeScript
متد sort که جزو متدهای توکار ES5 است، میتواند معادلی برای متد OrderBy باشد که جهت مرتب سازی عناصر یک لیست از آن استفاده میشود:
متد sort یک callback را میپذیرد و هر بار دو آیتم در حال مرتب سازی را به آن ارسال میکند. در این حالت اگر خروجی این callback:
- مساوی صفر باشد، تغییری را به وجود نمیآورد.
- کمتر از صفر باشد، اولین عنصر را قبل از دومین عنصر قرار میدهد.
- بیشتر از صفر باشد، دومین عنصر را پس از اولین عنصر قرار میدهد.
منطق مقایسهی فوق را به صورت ذیل نیز میتوان خلاصه کرد:
با این خروجی:
و یا اگر بخواهیم این لیست را بر اساس نام اشخاص مرتب سازی کنیم، به منطق ذیل خواهیم رسید:
با این خروجی:
نکتهی مهم: همانطور که ملاحظه میکنید، متد sort نه فقط یک خروجی مرتب شده را بازگشت دادهاست، بلکه اصل آرایه را نیز درجا مرتب سازی کردهاست و ترتیب عناصر این آرایه، دیگر با آرایهی قبلی و اصلی یکی نیست.
امکان ترکیب زنجیروار متدهای کار بر روی لیستها در TypeScript
همانند LINQ، در اینجا نیز میتوان متدهای فوق را به صورت زنجیروار بر روی یک لیست فراخوانی و اجرا کرد:
با این خروجی:
در اینجا ابتدا اشخاص بالای 30 سال فیلتر شدهاند. سپس فقط خاصیت رشتهای نام آنها انتخاب شدهاست و در آخر این نامها به صورت نزولی مرتب شدهاند.
معادل متد Skip در TypeScript
متد splice که جزو متدهای توکار ES5 است، میتواند شبیه به متد Skip عمل کند. این متد آرایهای را بازگشت میدهد که حاوی عناصری است که پس از تعداد ذکر شده، در آرایهی اصلی وجود دارند:
با این خروجی:
کار واقعی متد splice، حذف عناصر باقیماندهی در آرایهاست و خروجی آن دقیقا لیست موارد حذف شدهاست. به همین جهت است که در نتیجهی فوق، اکنون آرایهی اصلی تنها دارای دو عضو باقیمانده است (و دیگر با آرایهی اصلی و ابتدایی یکی نیست).
تدارک ساختار ابتدایی این مطلب
در اینجا اینترفیسی را که بیانگر ساختار شیء شخص است، به صورت ذیل ایجاد میکنیم:
export interface Person { name: string; age: number; }
export class LinqTestsComponent { people: Person[] = [ { name: "User 4", age: 27 }, { name: "User 5", age: 42 }, { name: "User 6", age: 8 }, { name: "User 1", age: 20 }, { name: "User 2", age: 35 }, { name: "User 3", age: 78 } ]; }
همچنین سه متد ذیل را نیز برای لاگ کردن عنوان آزمایش، نمایش محتوای آرایهی اصلی و نمایش نتیجهی آزمایش، به این کلاس اضافه میکنیم:
logTitle(title: string) { console.log(`%c${title}`, "background: #222; color: #bada55"); } logOriginalArray() { console.log(`original this.people:${JSON.stringify(this.people)}`); } logResult(message: string, result: any) { console.log(`${message}:${JSON.stringify(result)}`); }
معادل متد Where در TypeScript
متد filter که جزو متدهای توکار ES5 است، میتواند معادلی برای متد Where، جهت فیلتر کردن عناصر بر اساس یک خاصیت، یا چندین خاصیت باشد:
equivalentToWhere() { const youngerThan40 = this.people.filter(person => person.age < 40); // ECMAScript 5 this.logResult("People younger than 40", youngerThan40); // Filtering on Multiple Criteria const youngsters = this.people.filter( person => person.age < 40 && person.name.toLocaleLowerCase().indexOf("user") !== -1); this.logResult("Users younger than 40", youngsters); }
People younger than 40:[ {"name":"User 4","age":27}, {"name":"User 6","age":8}, {"name":"User 1","age":20}, {"name":"User 2","age":35} ] Users younger than 40:[ {"name":"User 4","age":27}, {"name":"User 6","age":8}, {"name":"User 1","age":20}, {"name":"User 2","age":35} ]
معادل متد Any در TypeScript
متد some که جزو متدهای توکار ES5 است، میتواند معادلی برای متد Any باشد. اگر یکی از عناصر آرایه، بر اساس شرط تعیین شده یافت شود، این متد مقدار true را باز میگرداند:
equivalentToAny() { const anyUnder40 = this.people.some(person => person.age < 40); // ECMAScript 5 this.logResult("Are any people under 40?", anyUnder40); // true // Filtering on Criteria Matching any Object Properties const filterBy = "user"; const anyUsers = this.people.filter(person => Object.keys(person).some(property => { let value = (<any>person)[property]; if (typeof value === "string") { value = value.toLocaleLowerCase(); } return value.toString().indexOf(filterBy) !== -1; }) ); this.logResult("anyUsers", anyUsers); }
Are any people under 40?:true anyUsers:[ {"name":"User 4","age":27}, {"name":"User 5","age":42}, {"name":"User 6","age":8}, {"name":"User 1","age":20}, {"name":"User 2","age":35}, {"name":"User 3","age":78} ]
در مثال دوم، جستجویی بر روی تمام خواص شیء شخص انجام شدهاست. در اینجا توسط متد Object.keys، لیست خواص شیء یافت شدهاست. سپس بر روی این لیست توسط متد some، بررسی شدهاست که آیا خاصیت رشتهای وجود دارد که مساوی عبارت filterBy باشد؟ حاصل این بررسی به عنوان شرط متد filter جهت بازگشت آرایهی متناظری از اشخاص یافت شده، استفاده شدهاست.
معادل متد Contains در TypeScript
متد includes که جزو متدهای توکار ES7 است، میتواند معادلی برای متد Contains باشد و کار آن بررسی وجود عنصری در یک لیست است:
equivalentToContains() { const searchElement: Person = { name: "User 4", age: 27 }; const containsUser4 = this.people.includes(searchElement); // ECMAScript 2016 = ECMAScript 7 this.logResult("Contains searchElement", containsUser4); // false -> only compares by reference and not by value. const indexOfUser4 = this.people.indexOf(searchElement); // ECMAScript 5 this.logResult("indexOfUser4", indexOfUser4); // -1 -> only compares by reference and not by value. const stringifiedObj = JSON.stringify(searchElement); const includesUser4 = this.people.some(person => JSON.stringify(person) === stringifiedObj); this.logResult("includesUser4", includesUser4); // true -> compares by by value. }
یکی از روشهای مقایسهی بر اساس تمام مقادیر خواص یک شیء، استفاده از متد JSON.stringify است که اگر آنرا با متد some ترکیب کنیم، میتوان به نتیجهی مطلوبی رسید:
Contains searchElement:false indexOfUser4:-1 includesUser4:true
معادل متد All در TypeScript
متد every که جزو متدهای توکار ES5 است، میتواند معادلی برای متد All باشد و کار آن بررسی صحت شرط اعمالی، بر روی تک تک عناصر لیست است. اگر این بررسی با موفقیت صورت گرفت، مقدار true را بازگشت میدهد:
equivalentToAll() { const allUnder30 = this.people.every(person => person.age < 30); // ECMAScript 5 this.logResult("Are all people under 30?", allUnder30); // false }
Are all people under 30?:false
معادل متدهای First و FirstOrDefault در TypeScript
میتوان از متدهای filter و یا find بومی ES5 و ES 6 برای شبیه سازی متدهای First (یافتن اولین عنصر درخواستی در یک لیست) و FirstOrDefault استفاده کرد:
equivalentToFirstOrDefault() { const vahidOrDefault = this.people.filter(item => item.name === "Vahid")[0] || null; // ECMAScript 5 this.logResult("vahidOrDefault", vahidOrDefault); const user1OrDefault = this.people.find(item => item.name === "User 1") || null; // ECMAScript 2015 = ECMAScript 6 this.logResult("user1OrDefault", user1OrDefault); }
معادل متد FindIndex در TypeScript
متد findIndex که جزو متدهای توکار ES6 است، میتواند معادلی برای متد FindIndex در جهت یافتن ایندکس عنصری در یک لیست، بر اساس شرط درخواستی، باشد.
equivalentToFindIndex() { const index = this.people.findIndex(person => person.age === 8); // ECMAScript 2015 = ECMAScript 6 this.logResult("index of the user with age 8", index) }
index of the user with age 8:2
معادل متد Select در TypeScript
متد map که جزو متدهای توکار ES5 است، میتواند معادلی برای متد Select، برای تغییر شکل نهایی خروجی یک لیست باشد:
equivalentToSelect() { const names = this.people.map(person => person.name); // ECMAScript 5 this.logResult("Selected the names of people", names); }
Selected the names of people:["User 4","User 5","User 6","User 1","User 2","User 3"]
معادل متد Aggregate در TypeScript
متد reduce که جزو متدهای توکار ES5 است، میتواند شبیه به متد Aggregate عمل کند و لیستی از عناصر را به یک مقدار کاهش دهد:
equivalentToAggregate() { // ECMAScript 5 const aggregate = this.people.reduce((person1, person2) => { return { name: "", age: person1.age + person2.age }; }); this.logResult("Aggregate age", aggregate.age); // { age: 210 } }
Aggregate age:210
معادل متد ForEach در TypeScript
متد forEach که جزو متدهای توکار ES5 است، میتواند معادلی برای متد ForEach باشد که روشی functional برای پیمودن عناصر یک لیست است:
equivalentToForEach() { // ECMAScript 5 this.people.forEach(person => { this.logResult("person", person); }); }
person:{"name":"User 4","age":27} person:{"name":"User 5","age":42} person:{"name":"User 6","age":8} person:{"name":"User 1","age":20} person:{"name":"User 2","age":35} person:{"name":"User 3","age":78}
معادل متد OrderBy در TypeScript
متد sort که جزو متدهای توکار ES5 است، میتواند معادلی برای متد OrderBy باشد که جهت مرتب سازی عناصر یک لیست از آن استفاده میشود:
// ECMAScript 5 let orderedByAgeAscending = this.people.sort((person1, person2) => { const a = person1.age; const b = person2.age; return a > b ? 1 : -1; }); this.logResult("Ordered by age ascending", orderedByAgeAscending);
- مساوی صفر باشد، تغییری را به وجود نمیآورد.
- کمتر از صفر باشد، اولین عنصر را قبل از دومین عنصر قرار میدهد.
- بیشتر از صفر باشد، دومین عنصر را پس از اولین عنصر قرار میدهد.
منطق مقایسهی فوق را به صورت ذیل نیز میتوان خلاصه کرد:
orderedByAgeAscending = this.people.sort((person1, person2) => person1.age - person2.age); this.logResult("Ordered by age ascending", orderedByAgeAscending);
Ordered by age ascending:[ {"name":"User 6","age":8}, {"name":"User 1","age":20}, {"name":"User 4","age":27}, {"name":"User 2","age":35}, {"name":"User 5","age":42}, {"name":"User 3","age":78} ]
const orderedByName = this.people.sort((person1, person2) => { // name1.localeCompare(name2) // is case insensitive // or use toUpperCase() to ignore character casing const name1 = person1.name.toUpperCase(); const name2 = person2.name.toUpperCase(); return name1 > name2 ? 1 : -1; }) this.logResult("Ordered by name", orderedByName); this.logOriginalArray();
Ordered by name:[ {"name":"User 1","age":20}, {"name":"User 2","age":35}, {"name":"User 3","age":78}, {"name":"User 4","age":27}, {"name":"User 5","age":42}, {"name":"User 6","age":8} ] original this.people:[ {"name":"User 1","age":20}, {"name":"User 2","age":35}, {"name":"User 3","age":78}, {"name":"User 4","age":27}, {"name":"User 5","age":42}, {"name":"User 6","age":8} ]
امکان ترکیب زنجیروار متدهای کار بر روی لیستها در TypeScript
همانند LINQ، در اینجا نیز میتوان متدهای فوق را به صورت زنجیروار بر روی یک لیست فراخوانی و اجرا کرد:
chainFunctionCalls() { const namesOfPeopleOver30OrderedDesc = this.people .filter(person => person.age > 30) .map(person => person.name) .sort((name1, name2) => { // name1.localeCompare(name2) // is case insensitive // or use toUpperCase() to ignore character casing name1 = name1.toUpperCase(); name2 = name2.toUpperCase(); return name2 > name1 ? 1 : -1; }); this.logResult("the names of all people over 30 ordered by name descending", namesOfPeopleOver30OrderedDesc); }
the names of all people over 30 ordered by name descending:["User 5","User 3","User 2"]
معادل متد Skip در TypeScript
متد splice که جزو متدهای توکار ES5 است، میتواند شبیه به متد Skip عمل کند. این متد آرایهای را بازگشت میدهد که حاوی عناصری است که پس از تعداد ذکر شده، در آرایهی اصلی وجود دارند:
equivalentToSkip() { const skip2 = this.people.splice(2); // ECMAScript 5 this.logResult("skip2 -> the deleted elements", skip2); this.logOriginalArray(); }
skip2 -> the deleted elements:[ {"name":"User 3","age":78}, {"name":"User 4","age":27}, {"name":"User 5","age":42}, {"name":"User 6","age":8} ] original this.people:[ {"name":"User 1","age":20}, {"name":"User 2","age":35} ]
Web-based applications run smoother if instead of using the traditional form method, they use JavaScript to post data to the server and to update the user interface after posting data: It also makes it easier to keep POST and GET actions separated. SignalR makes it even slicker; it can even update multiple pages at the same time. Is it time to use JavaScript to post data rather than posting via the browser the traditional way?
Latest #dotnetcore 3.0 runtime build just dropped the memory use of the #aspnetcore @TFBenchmarks benchmarks by half!
به صورت پیش فرض، Rx هر بار تنها یک مقدار را بررسی میکند. اما گاهی از اوقات نیاز است تا در هربار، بیشتر از یک مقدار دریافت و پردازش شوند. برای این منظور Rx متدهای الحاقی ویژهای را به نامهای Buffer ،Scan و Window تدارک دیدهاست تا بتواند از یک توالی، چندین توالی را تولید کند (توالی توالیها = Sequence of sequences).
متد Scan
فرض کنید قصد دارید تعدادی عدد را با هم جمع بزنید. برای اینکار عموما عدد اول با عدد دوم جمع زده شده و سپس حاصل آن با عدد سوم جمع زده خواهد شد و به همین ترتیب تا آخر توالی. کار متد Scan نیز دقیقا به همین نحو است. هربار که قرار است توالی پردازش شود، حاصل عملیات مرحلهی قبل را در اختیار مصرف کننده قرار میدهد.
در مثال ذیل، قصد داریم حاصل جمع اعداد موجود در آرایهای را بدست بیاوریم:
با این خروجی
در اولین بار اجرای متد Subscribe، کار مقدار دهی accumulator با اولین عنصر آرایه صورت میگیرد.
در دفعات بعدی، مقدار این accumulator با عدد جاری جمع زده شده و حاصل این عملیات در تکرار آتی، مجددا توسط accumulator قابل دسترسی خواهد بود.
یک نکته: اگر علاقمند باشیم که مقدار اولیهی accumulator، اولین عنصر توالی نباشد، میتوان آنرا توسط پارامتر seed متد Scan مقدار دهی کرد:
متد Buffer
متد بافر، کار تقسیم یک توالی را به توالیهای کوچکتر، بر اساس زمان، یا تعداد عنصر مشخص شده، انجام میدهد. برای مثال در برنامههای دسکتاپ شاید نیازی نباشد تا به ازای هر عنصر توالی، یکبار رابط کاربری را به روز کرد. عموما بهتر است تا تعداد مشخصی از عناصر یکجا پردازش شده و نتیجهی این پردازش به تدریج نمایش داده شود.
در اینجا نحوهی استفاده از متد بافر را به همراه مشخص کردن تعداد اعضای بافر ملاحظه میکنید. هربار که onNext متد Subscribe فراخوانی شود، 10 عنصر از توالی را در اختیار خواهیم داشت (بجای یک عنصر حالت متداول بافر نشده).
به این ترتیب میتوان فشار حجم اطلاعات ورودی با فرکانس بالا را کنترل کرد و در نتیجه از منابع موجود بهتر استفاده نمود. برای مثال اگر میخواهید عملیات bulk insert را انجام دهید، میتوان بر اساس یک batch size مشخص، گروه گروه اطلاعات را به بانک اطلاعاتی اضافه کرد تا فشار کار کاهش یابد.
همینکار را بر اساس زمان نیز میتوان انجام داد:
در مثال فوق هر 2 ثانیه یکبار، مجموعهای از عناصر به متد onNext ارسال خواهند شد.
متد Window
متد Window نیز دقیقا همان پارامترهای متد بافر را قبول میکند. با این تفاوت که هربار، یک توالی obsevable را به متد onNext ارسال میکند.
نوع numbers پارامتر onNext، در حین بکارگیری متد بافر در مثالهای فوق، IList of int است. اما اگر متدهای Buffer را تبدیل به متد Window کنیم، اینبار نوع numbers، معادل IObservable of int خواهد شد.
چه زمانی باید از Buffer استفاده کرد و چه زمانی از Window؟
در متد بافر، به ازای هر توالی که به پارامتر onNext ارسال میشود، یکبار وهلهی جدیدی از توالی مدنظر در حافظه ایجاد و ارسال خواهد شد. در متد Window صرفا اشارهگرهایی به این توالی را در اختیار داریم؛ بنابراین مصرف حافظهی کمتری را شاهد خواهیم بود. متد Window بسیار مناسب است برای اعمال aggregation. مثلا اگر نیاز است جمع، میانگین، حداقل و حداکثر عناصر دریافتی محاسبه شوند، بهتر است از متد Window استفاده شود که نهایتا قابلیت استفاده از متدهای الحاقی Sum و Max و Min را به همراه دارد. با این تفاوت که حاصل اینها نیز یک IObservable است که باید Subscribe آنرا برای دریافت نتیجه فراخوانی کرد:
در این حالت متد Window، برخلاف متد Buffer، توالی numbers را هربار کش نمیکند و به این ترتیب میتوان به مصرف حافظهی کمتری رسید.
کاربردهای دنیای واقعی
در اینجا دو مثال از بکارگیری متد Buffer را جهت پردازش مجموعههای عظیمی از اطلاعات و نمایش همزمان آنها در رابط کاربری ملاحظه میکنید.
مثال اول: فرض کنید قصد دارید تمام فایلهای درایو C خود را توسط یک TreeView نمایش دهید. در این حالت نباید رابط کاربری برنامه در حالت هنگ به نظر برسد. همچنین به علت زیاد بودن تعداد فایلها و نمایش همزمان آنها در UI، نباید CPU Usage برنامه تا حدی باشد که در کار سایر برنامهها اخلال ایجاد کند. در این مثالها با استفاده از Rx و متد بافر آن، هربار مثلا 1000 آیتم را بافر کرده و سپس یکجا در TreeView نمایش میدهند. به این ترتیب دو شرط یاد شده محقق میشوند.
The Rx Framework By Example
مثال دوم: خواندن تعداد زیادی رکورد از بانک اطلاعاتی به همراه نمایش همزمان آنها در UI بدون اخلالی در کار سیستم و همچنین هنگ کردن برنامه.
Using Reactive Extensions for Streaming Data from Database
متد Scan
فرض کنید قصد دارید تعدادی عدد را با هم جمع بزنید. برای اینکار عموما عدد اول با عدد دوم جمع زده شده و سپس حاصل آن با عدد سوم جمع زده خواهد شد و به همین ترتیب تا آخر توالی. کار متد Scan نیز دقیقا به همین نحو است. هربار که قرار است توالی پردازش شود، حاصل عملیات مرحلهی قبل را در اختیار مصرف کننده قرار میدهد.
در مثال ذیل، قصد داریم حاصل جمع اعداد موجود در آرایهای را بدست بیاوریم:
var sequence = new[] { 12, 3, -4, 7 }.ToObservable(); var runningSum = sequence.Scan((accumulator, value) => { Console.WriteLine("accumulator {0}", accumulator); Console.WriteLine("value {0}", value); return accumulator + value; }); runningSum.Subscribe(result => Console.WriteLine("result {0}\n", result));
result 12 accumulator 12 value 3 result 15 accumulator 15 value -4 result 11 accumulator 11 value 7 result 18
در دفعات بعدی، مقدار این accumulator با عدد جاری جمع زده شده و حاصل این عملیات در تکرار آتی، مجددا توسط accumulator قابل دسترسی خواهد بود.
یک نکته: اگر علاقمند باشیم که مقدار اولیهی accumulator، اولین عنصر توالی نباشد، میتوان آنرا توسط پارامتر seed متد Scan مقدار دهی کرد:
var runningSum = sequence.Scan(seed: 10, accumulator: (accumulator, value) =>
متد Buffer
متد بافر، کار تقسیم یک توالی را به توالیهای کوچکتر، بر اساس زمان، یا تعداد عنصر مشخص شده، انجام میدهد. برای مثال در برنامههای دسکتاپ شاید نیازی نباشد تا به ازای هر عنصر توالی، یکبار رابط کاربری را به روز کرد. عموما بهتر است تا تعداد مشخصی از عناصر یکجا پردازش شده و نتیجهی این پردازش به تدریج نمایش داده شود.
var sequence = Enumerable.Range(1, 200) .ToObservable() .Buffer(count: 10); sequence.Subscribe(onNext: numbers => { Console.WriteLine(numbers.Sum()); });
به این ترتیب میتوان فشار حجم اطلاعات ورودی با فرکانس بالا را کنترل کرد و در نتیجه از منابع موجود بهتر استفاده نمود. برای مثال اگر میخواهید عملیات bulk insert را انجام دهید، میتوان بر اساس یک batch size مشخص، گروه گروه اطلاعات را به بانک اطلاعاتی اضافه کرد تا فشار کار کاهش یابد.
همینکار را بر اساس زمان نیز میتوان انجام داد:
var sequence = Enumerable.Range(1, 200) .ToObservable() .Buffer(timeSpan: TimeSpan.FromSeconds(2));
متد Window
متد Window نیز دقیقا همان پارامترهای متد بافر را قبول میکند. با این تفاوت که هربار، یک توالی obsevable را به متد onNext ارسال میکند.
نوع numbers پارامتر onNext، در حین بکارگیری متد بافر در مثالهای فوق، IList of int است. اما اگر متدهای Buffer را تبدیل به متد Window کنیم، اینبار نوع numbers، معادل IObservable of int خواهد شد.
var sequence = Enumerable.Range(1, 200) .ToObservable() .Window(timeSpan: TimeSpan.FromSeconds(2)); sequence.Subscribe(onNext: numbers => { numbers.Subscribe(onNext: number => Console.WriteLine(number)); });
چه زمانی باید از Buffer استفاده کرد و چه زمانی از Window؟
در متد بافر، به ازای هر توالی که به پارامتر onNext ارسال میشود، یکبار وهلهی جدیدی از توالی مدنظر در حافظه ایجاد و ارسال خواهد شد. در متد Window صرفا اشارهگرهایی به این توالی را در اختیار داریم؛ بنابراین مصرف حافظهی کمتری را شاهد خواهیم بود. متد Window بسیار مناسب است برای اعمال aggregation. مثلا اگر نیاز است جمع، میانگین، حداقل و حداکثر عناصر دریافتی محاسبه شوند، بهتر است از متد Window استفاده شود که نهایتا قابلیت استفاده از متدهای الحاقی Sum و Max و Min را به همراه دارد. با این تفاوت که حاصل اینها نیز یک IObservable است که باید Subscribe آنرا برای دریافت نتیجه فراخوانی کرد:
var sequence = Enumerable.Range(1, 200) .ToObservable() .Window(10); sequence.Subscribe(onNext: numbers => { numbers.Sum().Subscribe(onNext: number => Console.WriteLine(number)); });
کاربردهای دنیای واقعی
در اینجا دو مثال از بکارگیری متد Buffer را جهت پردازش مجموعههای عظیمی از اطلاعات و نمایش همزمان آنها در رابط کاربری ملاحظه میکنید.
مثال اول: فرض کنید قصد دارید تمام فایلهای درایو C خود را توسط یک TreeView نمایش دهید. در این حالت نباید رابط کاربری برنامه در حالت هنگ به نظر برسد. همچنین به علت زیاد بودن تعداد فایلها و نمایش همزمان آنها در UI، نباید CPU Usage برنامه تا حدی باشد که در کار سایر برنامهها اخلال ایجاد کند. در این مثالها با استفاده از Rx و متد بافر آن، هربار مثلا 1000 آیتم را بافر کرده و سپس یکجا در TreeView نمایش میدهند. به این ترتیب دو شرط یاد شده محقق میشوند.
The Rx Framework By Example
مثال دوم: خواندن تعداد زیادی رکورد از بانک اطلاعاتی به همراه نمایش همزمان آنها در UI بدون اخلالی در کار سیستم و همچنین هنگ کردن برنامه.
Using Reactive Extensions for Streaming Data from Database