Eğitim
Modül
C# dilinde Dizileri ve foreach deyimini kullanarak veri dizilerini depolama ve yineleme - Training
Dizi değişkenleri oluşturmayı ve dizi öğeleri arasında yineleme yapmayı öğrenin.
Bu tarayıcı artık desteklenmiyor.
En son özelliklerden, güvenlik güncelleştirmelerinden ve teknik destekten faydalanmak için Microsoft Edge’e yükseltin.
Yazdığınız hemen her programın bir koleksiyon üzerinde yinelemesi gerekir. Koleksiyondaki her öğeyi inceleyen bir kod yazacaksınız.
Ayrıca, bu sınıfın öğeleri için yineleyici oluşturan yöntemler olan yineleyici yöntemleri de oluşturacaksınız. Yineleyici, özellikle listeler olmak üzere kapsayıcıdan geçen bir nesnedir. Yineleyiciler şu için kullanılabilir:
C# dili hem oluşturma hem de kullanma dizileri için özellikler sağlar. Bu diziler zaman uyumlu veya zaman uyumsuz olarak üretilebilir ve kullanılabilir. Bu makalede bu özelliklere genel bir bakış sağlanır.
Bir koleksiyonu listelemek basittir: foreach
anahtar sözcüğü bir koleksiyonu numaralandırır ve koleksiyondaki her öğe için katıştırılmış deyimi bir kez yürütür:
foreach (var item in collection)
{
Console.WriteLine(item?.ToString());
}
Hepsi bu kadar. Bir koleksiyonun tüm içeriğini yinelemek için ihtiyacınız foreach
olan tek şey deyimidir. Ama foreach
ifade sihirli değil. Bir koleksiyonu yinelemek için gereken kodu oluşturmak için .NET core kitaplığında tanımlanan iki genel arabirime dayanır: IEnumerable<T>
ve IEnumerator<T>
. Bu mekanizma aşağıda daha ayrıntılı olarak açıklanmıştır.
Bu arabirimlerin her ikisi de genel olmayan karşılıklara sahiptir: IEnumerable
ve IEnumerator
. Genel sürümler modern kod için tercih edilir.
Bir sıra zaman uyumsuz olarak oluşturulduğunda, sırayı await foreach
zaman uyumsuz olarak kullanmak için deyimini kullanabilirsiniz:
await foreach (var item in asyncSequence)
{
Console.WriteLine(item?.ToString());
}
Bir sıra bir System.Collections.Generic.IEnumerable<T>olduğunda kullanırsınız foreach
. Bir sıra bir System.Collections.Generic.IAsyncEnumerable<T>olduğunda kullanırsınız await foreach
. İkinci durumda, sıra zaman uyumsuz olarak oluşturulur.
C# dilinin bir diğer harika özelliği de numaralandırma için kaynak oluşturan yöntemler oluşturmanıza olanak tanır. Bu yöntemler yineleyici yöntemler olarak adlandırılır. Yineleyici yöntemi, istendiğinde bir dizideki nesnelerin nasıl oluşturulacağı tanımlar. Yineleyici yöntemi tanımlamak için bağlamsal anahtar sözcükleri kullanırsınız yield return
.
0 ile 9 arasında tamsayı dizisini oluşturmak için bu yöntemi yazabilirsiniz:
public IEnumerable<int> GetSingleDigitNumbers()
{
yield return 0;
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
yield return 6;
yield return 7;
yield return 8;
yield return 9;
}
Yukarıdaki kod, bir yineleyici yönteminde birden çok ayrık yield return
deyim kullanabileceğiniz gerçeğini vurgulamak için ayrı yield return
deyimleri gösterir. Yineleyici yönteminin kodunu basitleştirmek için diğer dil yapılarını kullanabilirsiniz (ve genellikle yapabilirsiniz). Aşağıdaki yöntem tanımı tam olarak aynı sayı dizisini oluşturur:
public IEnumerable<int> GetSingleDigitNumbersLoop()
{
int index = 0;
while (index < 10)
yield return index++;
}
Birini veya diğerini seçmek zorunda değilsin. Yönteminizin gereksinimlerini karşılamak için gereken sayıda yield return
deyiminiz olabilir:
public IEnumerable<int> GetSetsOfNumbers()
{
int index = 0;
while (index < 10)
yield return index++;
yield return 50;
index = 100;
while (index < 110)
yield return index++;
}
Yukarıdaki örneklerin tümünün zaman uyumsuz bir karşılığı olacaktır. Her durumda dönüş türünü IEnumerable<T>
ile IAsyncEnumerable<T>
değiştirirsiniz. Örneğin, önceki örnekte aşağıdaki zaman uyumsuz sürüm bulunur:
public async IAsyncEnumerable<int> GetSetsOfNumbersAsync()
{
int index = 0;
while (index < 10)
yield return index++;
await Task.Delay(500);
yield return 50;
await Task.Delay(500);
index = 100;
while (index < 110)
yield return index++;
}
Bu, hem zaman uyumlu hem de zaman uyumsuz yineleyiciler için söz dizimidir. Şimdi gerçek bir dünya örneğini ele alalım. Bir IoT projesinde olduğunuzu ve cihaz algılayıcılarının çok büyük bir veri akışı oluşturup oluşturmadığınızı düşünün. Veriler için bir his elde etmek için her N. veri öğesini örnekleyen bir yöntem yazabilirsiniz. Bu küçük yineleyici yöntemi şu hileyi yapar:
public static IEnumerable<T> Sample<T>(this IEnumerable<T> sourceSequence, int interval)
{
int index = 0;
foreach (T item in sourceSequence)
{
if (index++ % interval == 0)
yield return item;
}
}
IoT cihazından okuma zaman uyumsuz bir dizi oluşturursa, aşağıdaki yöntemin gösterdiği gibi yöntemini değiştirirsiniz:
public static async IAsyncEnumerable<T> Sample<T>(this IAsyncEnumerable<T> sourceSequence, int interval)
{
int index = 0;
await foreach (T item in sourceSequence)
{
if (index++ % interval == 0)
yield return item;
}
}
Yineleyici yöntemlerinde önemli bir kısıtlama vardır: aynı yöntemde hem deyim return
yield return
hem de deyim olamaz. Aşağıdaki kod derlenmez:
public IEnumerable<int> GetSingleDigitNumbers()
{
int index = 0;
while (index < 10)
yield return index++;
yield return 50;
// generates a compile time error:
var items = new int[] {100, 101, 102, 103, 104, 105, 106, 107, 108, 109 };
return items;
}
Bu kısıtlama normalde bir sorun değildir. Yöntemin tamamında kullanma yield return
veya özgün yöntemi birden çok yönteme ayırma seçeneğiniz vardır; bazıları ve kullananlarreturn
yield return
.
Son yöntemi her yerde kullanmak yield return
üzere biraz değiştirebilirsiniz:
public IEnumerable<int> GetFirstDecile()
{
int index = 0;
while (index < 10)
yield return index++;
yield return 50;
var items = new int[] {100, 101, 102, 103, 104, 105, 106, 107, 108, 109 };
foreach (var item in items)
yield return item;
}
Bazen doğru yanıt, yineleyici yöntemini iki farklı yönteme bölmektir. return
kullanan bir ve kullanan bir saniyeyield return
. Boole bağımsız değişkenine göre boş bir koleksiyon veya ilk beş tek sayı döndürmek isteyebileceğiniz bir durum düşünün. Bunu şu iki yöntem olarak yazabilirsiniz:
public IEnumerable<int> GetSingleDigitOddNumbers(bool getCollection)
{
if (getCollection == false)
return new int[0];
else
return IteratorMethod();
}
private IEnumerable<int> IteratorMethod()
{
int index = 0;
while (index < 10)
{
if (index % 2 == 1)
yield return index;
index++;
}
}
Yukarıdaki yöntemlere bakın. birincisi, boş bir koleksiyon veya ikinci yöntem tarafından oluşturulan yineleyiciyi döndürmek için standart return
deyimini kullanır. İkinci yöntem, istenen diziyi yield return
oluşturmak için deyimini kullanır.
deyimi, foreach
bir koleksiyonun tüm öğeleri arasında yinelemek için ve IEnumerator<T>
arabirimlerini kullanan IEnumerable<T>
standart bir deyime genişletir. Ayrıca, geliştiricilerin kaynakları düzgün yönetmeyerek yaptığı hataları da en aza indirir.
Derleyici, ilk örnekte gösterilen döngüleri foreach
şu yapıya benzer bir şeye çevirir:
IEnumerator<int> enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
var item = enumerator.Current;
Console.WriteLine(item.ToString());
}
Derleyici tarafından oluşturulan tam kod daha karmaşıktır ve tarafından GetEnumerator()
döndürülen nesnenin arabirimini uyguladığı IDisposable
durumları işler. Tam genişletme aşağıdakine benzer bir kod oluşturur:
{
var enumerator = collection.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var item = enumerator.Current;
Console.WriteLine(item.ToString());
}
}
finally
{
// dispose of enumerator.
}
}
Derleyici, ilk zaman uyumsuz örneği şu yapıya benzer bir şeye çevirir:
{
var enumerator = collection.GetAsyncEnumerator();
try
{
while (await enumerator.MoveNextAsync())
{
var item = enumerator.Current;
Console.WriteLine(item.ToString());
}
}
finally
{
// dispose of async enumerator.
}
}
Numaralandırıcının atılma şekli, türünün enumerator
özelliklerine bağlıdır. Genel zaman uyumlu durumda yan tümcesi finally
şu şekilde genişletir:
finally
{
(enumerator as IDisposable)?.Dispose();
}
Genel zaman uyumsuz durum şu şekilde genişletiliyor:
finally
{
if (enumerator is IAsyncDisposable asyncDisposable)
await asyncDisposable.DisposeAsync();
}
Ancak türü korumalı bir türse enumerator
ve veya türünden IAsyncDisposable
enumerator
IDisposable
finally
örtük dönüştürme yoksa yan tümcesi boş bir bloğa genişletilir:
finally
{
}
türünden enumerator
IDisposable
öğesine örtük bir dönüştürme varsa ve enumerator
boş değer atanamayan bir değer türündeyse, yan tümcesi finally
şu şekilde genişletilir:
finally
{
((IDisposable)enumerator).Dispose();
}
Neyse ki tüm bu ayrıntıları hatırlamanıza gerek yok. Deyimi foreach
tüm bu nüansları sizin için işler. Derleyici, bu yapılardan herhangi biri için doğru kodu oluşturur.
.NET geri bildirimi
.NET, açık kaynak bir projedir. Geri bildirim sağlamak için bir bağlantı seçin:
Eğitim
Modül
C# dilinde Dizileri ve foreach deyimini kullanarak veri dizilerini depolama ve yineleme - Training
Dizi değişkenleri oluşturmayı ve dizi öğeleri arasında yineleme yapmayı öğrenin.