Visual Studio "hızlı izleme" aracı ve lambda ifadelerinde hata ayıklama


96

5
Bu tamamlandı ve VS 2015 önizlemesinde mevcut. visualstudio.uservoice.com/forums/121579-visual-studio/…
Francisco d'Anconia


lambda ifadesi için MSDN'de verilen çok basit bir örneği denedim ama çalışmıyor. VS 2015 kurumsal
sürümüm var

2
@ Franciscod'Anconia'nın hata ayıklamada lambda desteğini etkinleştirmek için "Yönetilen Uyumluluk Modunu Kullan" seçeneğinin işaretlenmesi gerekir ( stackoverflow.com/a/36559817/818321 ) Sonuç olarak, koşullu kesme noktalarını kullanamazsınız: blogs.msdn .microsoft.com / devops / 2013/10/16 /… ve stackoverflow.com/a/35983978/818321
Nik

Yanıtlar:


64

Anonim yöntemler gibi Lambda ifadeleri de aslında çok karmaşık yaratıklardır. Expression(.NET 3.5) dışlasak bile , bu hala çok fazla karmaşıklık bırakıyor , en azından yakalanan değişkenler değil, onları kullanan kodu temelde yeniden yapılandırıyor (değişkenler olarak düşündüğünüz şey, derleyici tarafından üretilen sınıflarda alanlara dönüşüyor) , biraz duman ve aynalarla.

Bu nedenle, onları boşta kullanamamanıza hiç şaşırmadım - bu sihri destekleyen çok sayıda derleyici çalışması (ve perde arkasında tür oluşturma) var.


91

Hayır, saat / yereller / hemen pencerede lambda ifadelerini kullanamazsınız. Marc'ın da belirttiği gibi, bu inanılmaz derecede karmaşık. Yine de konuya biraz daha dalmak istedim.

Çoğu insanın hata ayıklayıcıda anonim bir işlevi yürütürken düşünmediği şey, bunun bir boşlukta oluşmamasıdır. Anonim bir işlevi tanımlama ve çalıştırma eylemi, kod tabanının temel yapısını değiştirir. Genel olarak ve özellikle yakın pencereden kodu değiştirmek çok zor bir iştir.

Aşağıdaki kodu düşünün.

void Example() {
  var v1 = 42;
  var v2 = 56; 
  Func<int> func1 = () => v1;
  System.Diagnostics.Debugger.Break();
  var v3 = v1 + v2;
}

Bu özel kod, v1 değerini yakalamak için tek bir kapanış oluşturur. Anonim bir işlev, kapsamı dışında bildirilmiş bir değişken kullandığında, kapatma yakalama gereklidir. Tüm niyet ve amaçlar için v1 artık bu işlevde mevcut değildir. Son satır aslında aşağıdakine daha çok benziyor

var v3 = closure1.v1 + v2;

Örnek işlevi hata ayıklayıcıda çalıştırılırsa, Kesme satırında duracaktır. Şimdi, kullanıcının aşağıdakileri izleme penceresine yazıp yazmadığını hayal edin

(Func<int>)(() => v2);

Bunu düzgün bir şekilde yürütmek için hata ayıklayıcının (veya daha uygun bir şekilde EE'nin) v2 değişkeni için bir kapanış yaratması gerekir. Bu zor ama imkansız değil.

Bunu EE için gerçekten zor bir iş yapan şey, bu son satırdır. Bu satır şimdi nasıl çalıştırılmalıdır? Tüm amaç ve amaçlar için anonim işlev, v2 değişkenini sildi ve onu closure2.v2 ile değiştirdi. Dolayısıyla, son kod satırının gerçekten şu anda okuması gerekiyor

var v3 = closure1.v1 + closure2.v2;

Yine de bu etkiyi kodda elde etmek için EE'nin aslında bir ENC eylemi olan son kod satırını değiştirmesi gerekir. Bu özel örnek mümkün olsa da, senaryoların iyi bir kısmı mümkün değil.

Daha da kötüsü, lambda ifadesinin yeni bir kapanış yaratmaması gerektiğidir. Aslında orijinal kapanışa veri eklemesi gerekir. Bu noktada doğrudan ENC sınırlamalarına girersiniz.

Benim küçük örneğim maalesef karşılaştığımız sorunların sadece yüzeyini çiziyor. Bu konu hakkında tam bir blog yazısı yazacağımı söyleyip duruyorum ve umarım bu hafta sonu vaktim olur.


41
Ağlamak, ağlamak, sıradanlığı kabul etmek, sızlanmak, sızlanmak. Hata ayıklayıcı, IDE'nin kalbidir ve siz onu kırdınız! İzleme penceresindeki Lambdaların hiçbir şeyi yakalamasına gerek yoktur. Diğer herhangi bir saat kodu gibi, yalnızca belirli bir yığın çerçevesinde anlam ifade eder. (Ya da değişkeni yakalarsınız, aynı değişken adına sahip başka bir işleve geçersiniz ... ve ne?) Hata ayıklayıcı, derleyiciyi hacklemek içindir. Çalışmasını sağla!
Aleksandr Dubinsky

2
Neden basitler ki, izleme penceresindeki lambdalarda yakalanan değişkenlere izin vermiyorlar. Basittir ve lambdaların sadece gerçekten işlevsel kodda kullanıldığı bir dizi hata ayıklama senaryosuna izin verir.
Luiz Felipe

@LuizFelipe bu bile hala çok büyük . EE'nin geri arama için tam işlev gövdesini gerçekten oluşturmasını gerektirir (IL'ye kadar). EE bugün bu türden bir şey yapmıyor, onun yerine bir tercüman.
JaredPar

1
@JaredPar bahsediyorsun sonrası üzüm posasını blog paylaşabilir
Ehsan Sajjad

49

Immediate veya Watch pencerelerinde lambda ifadelerini kullanamazsınız.

Bununla birlikte , .Where ("Id = @ 0", 2) biçimini alan System.Linq.Dynamic ifadelerini kullanabilirsiniz - standart Linq'te kullanılabilen tüm yöntemlere sahip değildir ve lambda ifadelerinin gücü, ama yine de hiç yoktan iyidir!


2
Peki ... diğerleri mümkün olmadığı halde açıklarken, bu en azından bize olası bir çözüm sağlıyor. +1
Nullius

1
Sadece açıklığa kavuşturmak için, "System.Linq.Dynamic" dosyasını içe aktarırsınız ve ardından hata ayıklama penceresinde "Where (something.AsQueryable," property> xyz ",
none

Bu harika. Linq Extension yöntemlerinin tamamını alamasanız bile, örneğin, yok .Any(string predicate), aşağıdaki gibi bir şey koyabilirsiniz: .Where("Id>2").Any()Watch Window veya Pin to Source. Bu harika!
Protector bir

22

Gelecek geldi!

Lambda ifadelerinde hata ayıklama desteği, Visual Studio 2015'e ( Yazma sırasında önizleme) eklenmiştir .

İfade Değerlendiricisinin yeniden yazılması gerekiyordu, pek çok özellik eksik: ASP.NET'te uzaktan hata ayıklama, Anında pencerede değişken bildirme, dinamik değişkenleri inceleme vb. Ayrıca yerel işlevlere çağrı gerektiren lambda ifadeleri şu anda desteklenmemektedir.


Görmek güzel. Güzel...!
Rahul Nikate 15



2

Lambda ifadeleri hata ayıklayıcının ifade değerlendiricisi tarafından desteklenmez ... ki bu şaşırtıcı değildir çünkü derleme zamanında ifadeler yerine yöntemler (veya İfade Ağaçları) oluşturmak için kullanılırlar (ekran .NET 2'ye geçerek Reflector'a bir göz atın) onları gör).

Ayrıca, tabii ki, başka bir yapı katmanı olan bir kapanış oluşturabilirler.


Eh, onlar olabilir yöntemleri oluşturmak; Expressionağaç oluşturabilirler - bu bağlama bağlıdır.
Marc Gravell

1

VS 2015'te bunu şimdi yapabilirsiniz, bu ekledikleri yeni özelliklerden biridir.


1

Hala Visual Studio 2013 kullanmanız gerekiyorsa, paket yöneticisi konsolu penceresini de kullanarak hemen pencerede bir döngü veya lambda ifadesi yazabilirsiniz. Benim durumumda, işlevin en üstüne bir liste ekledim:

private void RemoveRoleHierarchy()
{
    #if DEBUG
    var departments = _unitOfWork.DepartmentRepository.GetAll().ToList();
    var roleHierarchies = _unitOfWork.RoleHierarchyRepository.GetAll().ToList();
    #endif

    try
    {
        //RoleHierarchy
        foreach (SchoolBo.RoleHierarchy item in _listSoRoleHierarchy.Where(r => r.BusinessKeyMatched == false))
            _unitOfWork.RoleHierarchyRepository.Remove(item.Id);

        _unitOfWork.Save();
    }
    catch (Exception e)
    {
        Debug.WriteLine(e.ToString());
        throw;
    }
}

GetAll()Fonksiyonum nerede :

private DbSet<T> _dbSet;

public virtual IList<T> GetAll()
{
    List<T> list;
    IQueryable<T> dbQuery = _dbSet;
    list = dbQuery
        .ToList<T>();

    return list;
}

Burada şu hatayı almaya devam ettim, bu yüzden çeşitli depolardaki tüm öğeleri yazdırmak istedim:

InnerException {"DELETE ifadesi REFERENCE kısıtlaması \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ "ile çelişti. Çakışma \" CC_Portal_SchoolObjectModel \ "veritabanında, tablo \" dbo.Department \ ", 'OranizationalRoleId' sütununda meydana geldi. ifade sonlandırıldı. "} System.Exception {System.Data.SqlClient.SqlException}

Ardından, hemen pencerede bunu çalıştırarak departman havuzunda kaç kayıt olduğunu buluyorum:

_unitOfWork.DepartmentRepository.GetAll().ToList().Count

243 döndü.

Bu nedenle, paket yöneticisi konsolunda aşağıdakileri yürütürseniz, tüm öğeleri yazdırır:

PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i }

Fikir yazarı burada bulunabilir


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.