SORU
11 Mayıs 2015, PAZARTESİ


Neden bu dize, uzatma yöntemi bir istisna değildir?

Bir dize içinde bir alt dize tüm dizinler IEnumerable<int> döndürmesi için bir C var# string uzantısı yöntemi. Bu mükemmel çalışıyor kullanım amacı ve beklenen sonuçları döndürülür (olarak kanıtlanmış tek yaptığım testler olmamakla birlikte aşağıda), ama başka bir birim test keşfetti bir sorun: bunu yapamazsın boş argümanlar.

İşte uzatma yöntemi test ediyorum:

public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
    if (searchText == null)
    {
        throw new ArgumentNullException("searchText");
    }
    for (int index = 0; ; index  = searchText.Length)
    {
        index = str.IndexOf(searchText, index);
        if (index == -1)
            break;
        yield return index;
    }
}

Burada sorun işaretlenmiş test:

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Extensions_AllIndexesOf_HandlesNullArguments()
{
    string test = "a.b.c.d.e";
    test.AllIndexesOf(null);
}

Test uzatma yöntemim karşı çalıştığında, başarısız olur, bu yöntem standart bir hata mesajı ile "istisna değil".

Açıkça işlev null geçtim, nedense karşılaştırma null == null false dönüyor yine. bu kafa karıştırıcı: Bu nedenle, bir istisna atılır ve kod devam ediyor.

Ben teyit bu hata ile testi: ne zaman çalışan bir yöntem benim ana proje ile arama Console.WriteLine null-karşılaştırma if blok, bir şey gösterilen konsol ve bir istisna değildir tarafından yakalanan herhangi bir catch blok ekliyorum. Ayrıca, == null yerine string.IsNullOrEmpty kullanarak aynı sorun var.

Neden bu sözüm ona basit bir karşılaştırma başarısız mı?

CEVAP
11 Mayıs 2015, PAZARTESİ


yield return kullanıyorsunuz. Bunu yaparken, derleyici devlet bir makine uygulayan oluşturulan bir sınıf döndüren bir işlev içine yönteminizi yeniden.

Genel olarak konuşursak, bu sınıfın alanlar için yerli yazar ve yield return Talimatlar arasında algoritması her bir parçası bir devlet haline gelir. Bu yöntem, derleme sonra ne olacağını bir önizleme (yield return yetiştirip, akıllı yazılım kapatmak için emin olun) ile kontrol edebilirsiniz.

Ama alt satırında:yöntem kod yineleme başlayana kadar idam olmayacak.

Ön koşulları kontrol etmek için her zamanki gibi iki yöntem ayrı ayrı

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 ilk yöntem beklediğiniz gibi davranır çünkü işleri (acil çalıştırma) ve devlet Makine İkinci yöntem tarafından hayata döndürür.

Ayrıca uzantıları yöntem çünkü null str parametre kontrol etmeniz gerektiğini unutmayınolabilirnull değerleri üzerine denir, sadece sözdizimsel şeker.


Eğer derleyici kodunuzu yaptıklarını merak ediyorsanız, işte size yöntemi, dotPeek kullanarak ile decompiledHaritayı Derleyici tarafından üretilen Kodseçeneği.

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 bir C# kodu, çünkü derleyici izin verilen şeyleri dile gelmez, ama izin veren yasal IL - mesela adlandırma değişkenleri bir yol olamazdı önlemek için Ad çakışması.

Ama gördüğünüz gibi, sadece bazı devlet başlatır kimin AllIndexesOf sadece oluşturur ve döndürür bir nesne,. GetEnumerator tek kopya nesne. Asıl iş sıralanıyor (MoveNext yöntemini çağırarak) başlattığınızda yapılır.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Atlantic Records

    Atlantic Rec

    15 Aralık 2006
  • discokatze

    discokatze

    23 EYLÜL 2009
  • Matthew Morrill

    Matthew Morr

    15 EKİM 2011