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 return
talimatlar 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 str
için parametre null
uzantıları yöntemler nedeniyle, olabilir çağrılacak null
değ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, AllIndexesOf
yalnızca kurucusu yalnızca bir durumu başlatan bir nesneyi oluşturur ve döndürür. GetEnumerator
yalnızca nesneyi kopyalar. Asıl iş, numaralandırmaya başladığınızda ( MoveNext
yöntemi çağırarak ) yapılır.