Step 5/7 : RUN npm i ---> [Warning] The requested image's platform (linux/amd64) does not match the detected host platform (windows/amd64) and no specific platform was requested ---> Running in dc37481d5781 added 48 packages, and audited 49 packages in 6s found 0 vulnerabilities npm notice npm notice New minor version of npm available! 8.5.5 -> 8.7.0 npm notice Changelog: <https://github.com/npm/cli/releases/tag/v8.7.0> npm notice Run `npm install -g npm@8.7.0` to update! npm notice The command '/bin/sh -c npm i' returned a non-zero code: 4294967295: failed to shutdown container: container dc37481d5781615dbf01c129f2322f06fcac8851a8a4078a6273438a8427254a encountered an error during hcsshim::System::waitBackground: failure in a Windows system call: The virtual machine or container with the specified identifier is not running. (0xc0370110): subsequent terminate failed container dc37481d5781615dbf01c129f2322f06fcac8851a8a4078a6273438a8427254a encountered an error during hcsshim::System::waitBackground: failure in a Windows system call: The virtual machine or container with the specified identifier is not running. (0xc0370110)
AngularJS #1
NET Core 3.1 Preview 2. منتشر شد
کتابخانه dynamic-table
آموزش مقدمات Angularjs
در این مقاله میخواهیم نحوهٔ ساخت اشیایی با خصوصیات Enumerable را بررسی کنیم. بررسی ویژگی این اشیاء دارای اهمیت است حداقل به این دلیل که پایهٔ یکی از قابلیت مهم زبانی سیشارپ یعنی LINQ هستند. برای یافتن پیشزمینهای در این موضوع خواندن این مقالههای بسیار خوب (۱ و ۲) نیز توصیه میشود.
Enumerableها
اشیاء Enumerable یا بهعبارت دیگر اشیائی که اینترفیس IEnumerable را پیادهسازی میکنند، دامنهٔ گستردهای از Collectionهای CLI را شامل میشوند. همانطور که در نمودار زیر نیز میتوانید مشاهده کنید IEnumerable (از نوع غیر Generic آن) در بالای سلسله مراتب اینترفیسهای Collectionهای CLI قرار دارد:
درخت اینترفیسهای Collectionها در CLI منبع
IEnumerableها همچنین دارای اهمیت دیگری نیز هستند؛ قابلیتهای LINQ که از داتنت ۳.۵ به داتنت اضافه شدند بهعنوان Extensionهای این اینترفیس تعریف شدهاند و پیادهسازی Linq to Objects را میتوانید در کلاس استاتیک System.Linq.Enumerable در System.Core مشاهده کنید. (میتوانید برای دیدن آن را با ILDasm یا Reflector باز کنید یا پیادهسازی آزاد آن در پروژهٔ Mono را اینجا مشاهده کنید که برای شناخت بیشتر LINQ واقعاً مفید است.)
همچنین این Enumerableها هستند که foreach را امکانپذیر میکنند. به عبارتی دیگر هر شئای که قرار باشد در foreach (var x in object) قرار بگیرد و بدین طریق اشیاء درونیاش را برای پیمایش یا عملی خاص قرار دهد باید Enumerable باشد.
همانطور که قبلاً هم اشاره شد IEnumerable از نوع غیر Generic در بالای نمودار Collectionها قرار دارد و حتی IEnumerable از نوع Generic نیز باید آن را پشتیبانی کند. این موضوع به احتمال به این دلیل در طراحی لحاظ شد که مهاجرت به .NET 2.0 که قابلیتهای Generic را افزوده بود سادهتر کند. IEnumerable همچنین قابلیت covariance که از قابلیتهای جدید C# 4.0 هست را دارا است (در اصل IEnumerable دارای Generic از نوع out است).
Enumerableها همانطور که از اسم اینترفیس IEnumerable انتظار میرود اشیایی هستند که میتوانند یک شئ Enumerator که IEnumerator را پیادهسازی کردهاست را از خود ارائه دهند. پس طبیعی است برای فهم و درک دلیل وجودی Enumerable باید Enumerator را بررسی کنیم.
Enumeratorها
Enumerator شئ است که در یک پیمایش یا بهعبارت دیگر گذر از روی تکتک عضوها ایجاد میشود که با حفظ موقعیت فعلی و پیمایش امکان ادامهٔ پیمایش را برای ما فراهم میآورد. اگر بخواهید آن را در حقیقت بازسازی کنید شئ Enumerator بهمانند کاغذ یا جسمی است که بین صفحات یک کتاب قرار میدهید که مکانی که در آن قرار دارید را گم نکنید؛ در این مثال، Enumerable همان کتاب است که قابلیت این را دارد که برای پیمایش به وسیلهٔ قرار دادن یک جسم در وسط آن را دارد.
حال برای اینکه دید بهتری از رابطهٔ بین Enumerable و Enumerator از نظر برنامهنویسی به این موضوع پیدا کنیم یک کد نمونهٔ عملی را بررسی میکنیم.
در اینجا نمونهٔ ساده و خوانایی از استفاده از یک List برای پیشمایش تمامی اعداد قرار دارد:
List<int> list = new List<int>(); list.Add(1); list.Add(2); list.Add(3); foreach (int i in list) { Console.WriteLine(i); }
همانطور که قبلاً اشاره foreach نیاز به یک Enumerable دارد و List هم با پیادهسازی IList که گسترشی از IEnumerable هست نیز یک نوع Enumerable هست. اگر این کد را Compile کنیم و IL آن را بررسی کنیم متوجه میشویم که CLI در اصل چنین کدی را برای اجرا میبینید:
List<int> list = new List<int>(); list.Add(1); list.Add(2); list.Add(3); IEnumerator<int> listIterator = list.GetEnumerator(); while (listIterator.MoveNext()) { Console.WriteLine(listIterator.Current); } listIterator.Dispose();
(میتوان از using استفاده نمود که Dispose را خود انجام دهد که اینجا برای سادگی استفاده نشدهاست.)
همانطور که میبینیم یک Enumerator برای Enumerable ما (یعنی List) ایجاد شد و پس از آن با پرسش این موضوع که آیا این پیمایش امکان ادامه دارد، کل اعضا پیمودهشده و عمل مورد نظر ما بر آنها انجام شدهاست.
خب، تا اینجای کار با خصوصیات و اهمیت Enumeratorها و Enumerableها آشنا شدیم، حال نوبت به آن میرسد که بررسی کنیم آنها را چگونه میسازند و بعد از آن با کاربردهای فراتری از آنها نسبت به پیمایش یک List آشنا شویم.
ساخت Enumeratorها و Enumerableها
همانطور که اشاره شد ایجاد اشیاء Enumerable به اشیاء Enumerator مربوط است، پس ما در یک قطعه کد که پیمایش از روی یک آرایه را فراهم میآورد ایجاد هر دوی آنها و رابطهٔ بینشان را بررسی میکنیم.
public class ArrayEnumerable<T> : IEnumerable<T> { private T[] _array; public ArrayEnumerable(T[] array) { _array = array; } public IEnumerator<T> GetEnumerator() { return new ArrayEnumerator<T>(_array); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class ArrayEnumerator<T> : IEnumerator<T> { private T[] _array; public ArrayEnumerator(T[] array) { _array = array; } public int index = -1; public T Current { get { return _array[index]; } } object System.Collections.IEnumerator.Current { get { return this.Current; } } public bool MoveNext() { index++; return index < _array.Length; } public void Reset() { index = 0; } public void Dispose() { } }
متدهای توکار استفاده از نوع دادهای XML - قسمت اول
- query : xml را به عنوان ورودی گرفته و نهایتا یک خروجی XML دیگر را بر میگرداند.
- exist : خروجی bit دارد؛ true یا false. ورودی آن یک XQuery است.
- value : یک خروجی SQL Type را ارائه میدهد.
- nodes : خروجی جدولی دارد.
- modify : برای تغییر اطلاعات بکار میرود.
استفاده از متد exist به عنوان جایگزین سبک وزن XML Schema
یکی از کاربردهای متد exist، تعریف قید بر روی یک ستون XML ایی جدول است. این روش، راه حل دوم و سادهای است بجای استفاده از XML Schema برای ارزیابی و اعتبارسنجی کل سند. پیشنیاز اینکار، تعریف قید مدنظر توسط یک تابع جدید است:
CREATE FUNCTION dbo.checkPerson(@data XML) RETURNS BIT WITH SCHEMABINDING AS BEGIN RETURN @data.exist('/people/person') END GO CREATE TABLE tblXML ( id INT PRIMARY KEY, doc XML CHECK(dbo.checkPerson(doc)=1) ) GO
اکنون برای آزمایش آن خواهیم داشت:
INSERT INTO tblXML (id, doc) VALUES ( 1, '<people><person name="Vahid"/></people>' ) INSERT INTO tblXML (id, doc) VALUES ( 2, '<people><emp name="Vahid"/></people>' )
The INSERT statement conflicted with the CHECK constraint "CK__tblXML__doc__060DEAE8". The conflict occurred in database "testdb", table "dbo.tblXML", column 'doc'. The statement has been terminated.
استفاده از متد value برای دریافت اطلاعات
با کاربرد مقدماتی متد value در بازگشت یک مقدار scalar در قسمتهای قبل آشنا شدیم. در ادامه مثالهای کاربردیتر را بررسی خواهیم کرد.
ابتدا جدول زیر را با یک ستون XML در آن درنظر بگیرید:
CREATE TABLE xml_tab ( id INT IDENTITY PRIMARY KEY, xml_col XML )
INSERT INTO xml_tab VALUES ('<people><person name="Vahid"/></people>') INSERT INTO xml_tab VALUES ('<people><person name="Farid"/></people>')
SELECT id, xml_col.value('(/people/person/@name)[1]', 'varchar(50)') AS name FROM xml_tab
یک نکته
اگر نیاز به خروجی از نوع XML است، بهتر است از متد query که در دو قسمت قبل بررسی شد، استفاده گردد. خروجی متد query همیشه یک untyped XML است یا نال. البته میتوان خروجی آنرا به یک typed XML دارای Schema نیز نسبت داد. در اینجا اعتبارسنجی در حین انتساب صورت خواهد گرفت.
استفاده از متد value برای تعریف قیود
از متد value همچنین میتوان برای تعریف قیود پیشرفته نیز استفاده کرد. برای مثال فرض کنیم میخواهیم ویژگی Id سند XML در حال ذخیره شدن، حتما مساوی ستون Id جدول باشد. برای این منظور ابتدا نیاز است همانند قبل یک تابع جدید را ایجاد نمائیم:
CREATE FUNCTION getIdValue(@doc XML) RETURNS int WITH SCHEMABINDING AS BEGIN RETURN @doc.value('/*[1]/@Id', 'int') END
سپس از این تابع در عبارت check برای مقایسه ویژگی Id سند XML در حال ذخیره شدن و id ردیف جاری استفاده میشود:
CREATE TABLE docs_tab ( id INT PRIMARY KEY, doc XML, CONSTRAINT id_chk CHECK(dbo.getIdValue(doc)=id) )
در ادامه برای آزمایش آن خواهیم داشت:
INSERT INTO docs_tab (id, doc) VALUES ( 1, '<Invoice Id="1"/>' ) INSERT INTO docs_tab (id, doc) VALUES ( 2, '<Invoice Id="1"/>' )
The INSERT statement conflicted with the CHECK constraint "id_chk". The conflict occurred in database "testdb", table "dbo.docs_tab". The statement has been terminated.
استفاده از متد value برای تعریف primary key
پیشتر عنوان شد که از فیلدهای XML نمیتوان به عنوان کلید یک جدول استفاده کرد؛ چون امکان مقایسهی محتوای کل آنها وجود ندارد. اما با استفاده از متد value میتوان مقدار دریافتی را به عنوان یک کلید اصلی محاسبه شده، ثبت کرد:
CREATE TABLE Invoices ( doc XML, id AS dbo.getIdValue(doc) PERSISTED PRIMARY KEY )
برای آزمایش آن سعی میکنیم دو رکورد را که حاوی ویژگی id برابری هستند، ثبت کنیم:
INSERT INTO Invoices VALUES ( '<Invoice Id="1"/>' ) INSERT INTO Invoices VALUES ( '<Invoice Id="1"/>' )
Violation of PRIMARY KEY constraint 'PK__Invoices__3213E83F145C0A3F'. Cannot insert duplicate key in object 'dbo.Invoices'. The duplicate key value is (1). The statement has been terminated.
توابع دسترسی به مقدار دادهها در XQuery
تابع data ، string و text برای دسترسی به مقدار دادهها در XQuery پیش بینی شدهاند.
اگر سعی کنیم مثال زیر را اجرا نمائیم:
DECLARE @doc XML SET @doc = '<foo bar="baz" />' SELECT @doc.query('/foo/@bar')
XQuery [query()]: Attribute may not appear outside of an element
DECLARE @doc XML SET @doc = '<foo bar="baz" />' SELECT @doc.query('data(/foo/@bar)')
DECLARE @x XML SET @x = '<x>hello<y>world</y></x><x>again</x>' SELECT @x.query('data(/*)')
اما اگر همین مثال را با متد string اجرا کنیم:
DECLARE @x XML SET @x = '<x>hello<y>world</y></x><x>again</x>' SELECT @x.query('string(/*)')
XQuery [query()]: 'string()' requires a singleton (or empty sequence), found operand of type 'element(*,xdt:untyped) *'
SELECT @x.query('string(/*[1])')
برای دریافت تمام کلمات توسط متد string میتوان از اسلش کمک گرفت:
SELECT @x.query('string(/)')
نمونهی دیگر آن مثال زیر است:
DECLARE @x XML = '<age>12</age>' SELECT @x.query('string(/age[1])')
متد text اندکی متفاوت عمل میکند. برای بررسی آن، ابتدا یک schema collection جدید را تعریف میکنیم که داری تک المانی رشتهای است به نام Root.
CREATE XML SCHEMA COLLECTION root_el AS '<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:geo"> <xs:element name="Root" type="xs:string" /> </xs:schema> ' GO
DECLARE @xmlDoc XML SET @xmlDoc = '<g:Root xmlns:g="urn:geo">datadata...</g:Root>' SELECT @xmlDoc.query(' declare namespace g="urn:geo"; /g:Root/text() ')
DECLARE @xmlDoc XML(root_el) SET @xmlDoc = '<g:Root xmlns:g="urn:geo">datadata...</g:Root>' SELECT @xmlDoc.query(' declare namespace g="urn:geo"; /g:Root[1]/text() ')
XQuery [query()]: 'text()' is not supported on simple typed or 'http://www.w3.org/2001/XMLSchema#anyType' elements, found 'element(g{urn:geo}:Root,xs:string) *'.
DECLARE @xmlDoc XML(root_el) SET @xmlDoc = '<g:Root xmlns:g="urn:geo">datadata...</g:Root>' SELECT @xmlDoc.query(' declare namespace g="urn:geo"; data(/g:Root[1]) ')
data(/age/text())