Kullanıyorsun yield return. Bunu yaparken, derleyici yönteminizi bir durum makinesini uygulayan üretilmiş bir sınıfı döndüren bir işleve yeniden yazar.
Genel olarak konuşursak, yerelleri o sınıfın alanlarına yeniden yazar ve algoritmanızın yield returntalimatlar arasındaki her parçası bir durum haline gelir. Derlemeden sonra bu yöntemin ne hale geldiğini bir derleyici ile kontrol edebilirsiniz (üretecek akıllı derlemeyi kapattığınızdan emin olun yield return).
Ancak sonuç şu: yönteminizin kodu, siz yinelemeye başlayana kadar çalıştırılmayacaktır.
Ön koşulları kontrol etmenin olağan yolu, yönteminizi ikiye bölmektir:
public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
if (str == null)
throw new ArgumentNullException("str");
if (searchText == null)
throw new ArgumentNullException("searchText");
return AllIndexesOfCore(str, searchText);
}
private static IEnumerable<int> AllIndexesOfCore(string str, string searchText)
{
for (int index = 0; ; index += searchText.Length)
{
index = str.IndexOf(searchText, index);
if (index == -1)
break;
yield return index;
}
}
Bu işe yarar çünkü ilk yöntem beklediğiniz gibi davranır (anında yürütme) ve ikinci yöntem tarafından uygulanan durum makinesini döndürür.
Ayrıca kontrol etmesi gerektiğini unutmayın striçin parametre nulluzantıları yöntemler nedeniyle, olabilir çağrılacak nulldeğerler onlar sadece sözdizimsel şeker konum olarak.
Derleyicinin kodunuza ne yaptığını merak ediyorsanız, derleyicinin ürettiği Kodu Göster seçeneğini kullanarak dotPeek ile derlenen yönteminiz burada .
public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
Test.<AllIndexesOf>d__0 allIndexesOfD0 = new Test.<AllIndexesOf>d__0(-2);
allIndexesOfD0.<>3__str = str;
allIndexesOfD0.<>3__searchText = searchText;
return (IEnumerable<int>) allIndexesOfD0;
}
[CompilerGenerated]
private sealed class <AllIndexesOf>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
{
private int <>2__current;
private int <>1__state;
private int <>l__initialThreadId;
public string str;
public string <>3__str;
public string searchText;
public string <>3__searchText;
public int <index>5__1;
int IEnumerator<int>.Current
{
[DebuggerHidden] get
{
return this.<>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden] get
{
return (object) this.<>2__current;
}
}
[DebuggerHidden]
public <AllIndexesOf>d__0(int <>1__state)
{
base..ctor();
this.<>1__state = param0;
this.<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
Test.<AllIndexesOf>d__0 allIndexesOfD0;
if (Environment.CurrentManagedThreadId == this.<>l__initialThreadId && this.<>1__state == -2)
{
this.<>1__state = 0;
allIndexesOfD0 = this;
}
else
allIndexesOfD0 = new Test.<AllIndexesOf>d__0(0);
allIndexesOfD0.str = this.<>3__str;
allIndexesOfD0.searchText = this.<>3__searchText;
return (IEnumerator<int>) allIndexesOfD0;
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator) this.System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
}
bool IEnumerator.MoveNext()
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
if (this.searchText == null)
throw new ArgumentNullException("searchText");
this.<index>5__1 = 0;
break;
case 1:
this.<>1__state = -1;
this.<index>5__1 += this.searchText.Length;
break;
default:
return false;
}
this.<index>5__1 = this.str.IndexOf(this.searchText, this.<index>5__1);
if (this.<index>5__1 != -1)
{
this.<>2__current = this.<index>5__1;
this.<>1__state = 1;
return true;
}
goto default;
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
void IDisposable.Dispose()
{
}
}
Bu geçersiz C # kodudur, çünkü derleyicinin dilin izin vermediği, ancak IL'de yasal olan şeyleri yapmasına izin verilir - örneğin değişkenleri ad çakışmalarını önleyemeyeceğiniz şekilde adlandırmak.
Ancak görebileceğiniz gibi, AllIndexesOfyalnızca kurucusu yalnızca bir durumu başlatan bir nesneyi oluşturur ve döndürür. GetEnumeratoryalnızca nesneyi kopyalar. Asıl iş, numaralandırmaya başladığınızda ( MoveNextyöntemi çağırarak ) yapılır.