Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Lowering in C#: What really happens with your code?, from NDC Oslo 2019

44 visualizaciones

Publicado el

Slides from my talk given at NDC Oslo, about what the compiler does when you write a foreach loop, among others.

Publicado en: Software
  • Sé el primero en comentar

  • Sé el primero en recomendar esto

Lowering in C#: What really happens with your code?, from NDC Oslo 2019

  1. 1. @davidwengier Lowering in C# What’s really going on in your code? David Wengier Microsoft NDC { Oslo } 2019
  2. 2. @davidwengier foreach (int item in listOfInts) { // do something with item } for (int i = 0; i < listOfInts.Count; i++) { int item = listOfInts[i]; // do something with item } int i = 0; while (i < listOfInts.Count) { int item = listOfInts[i]; // do something with item i++; } int i = 0; again: int item = listOfInts[i]; // do something with item i++; if (i < listOfInts.Count) { goto again; } IL_0024: ldloc.0 IL_0025: ldloc.1 IL_0026: callvirt instance !0 class [mscorlib]List`1<int32>::get_Item(int32) IL_002b: pop IL_002c: ldloc.1 IL_002d: ldc.i4.1 IL_002e: add IL_002f: stloc.1 IL_0030: ldloc.1 IL_0031: ldloc.0 IL_0032: callvirt instance int32 class [mscorlib]List`1<int32>::get_Count() IL_0037: blt.s IL_0024 What is lowering? IL foreach for while gotogoto while for foreach
  3. 3. @davidwengier What is lowering? “A common technique … is to have the compiler “lower” from high-level language features to low-level language features in the same language.” Eric Lippert https://ericlippert.com/2014/04/28/lowering-in-language-design-part-one/
  4. 4. @davidwengier LINQ from c in customers where c.Country == “AU” select c;
  5. 5. @davidwengier LINQ customers.Where(c => c.Country == “AU”) .Select(c => c);
  6. 6. @davidwengier LINQ Enumerable.Select( Enumerable.Where(customers, c => c.Country == “AU”), c => c);
  7. 7. @davidwengier LINQ Enumerable.Select( Enumerable.Where(customers, FilterCustomers), SelectCustomer); bool FilterCustomers(Customer c) { return c.Country == “AU”; } Customer SelectCustomer(Customer c) { return c; }
  8. 8. @davidwengier var message = "NDC Oslo"; decimal message = 5M; string message = "NDC " + "Oslo"; string message = part1 + part2;
  9. 9. @davidwengier Why do I want to know? string message = "You have " + count + " items"; string message = $"You have {count} items"; string message = string.Format("You have {0} items", count);
  10. 10. @davidwengier foreach foreach (int m in values) { Console.WriteLine(m); }
  11. 11. @davidwengier IEnumerable interface IEnumerable { IEnumerator GetEnumerator(); } interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); } interface IEnumerable<T> : IEnumerable { new IEnumerator<T> GetEnumerator(); } interface IEnumerator<T> : IEnumerator, IDisposable { new T Current { get; } }
  12. 12. @davidwengier foreach { var e = values.GetEnumerator(); try { int m; while (e.MoveNext()) { m = (int)(int)e.Current; Console.WriteLine(m); } } finally { if (e != null && e is IDisposable) { ((IDisposable)e).Dispose(); } } } object[] v = new [] { 1, 2 }; Write(v); void Write(object[] arr) { foreach (int s in arr) { Console.WriteLine(s); } } Person[] v = new [] { Empl(),..}; Write(v); void Write(Person[] arr) { foreach (Customer c in arr) { Handle(c); } }
  13. 13. @davidwengier foreach (C# 5+) { var e = values.GetEnumerator(); try { while (e.MoveNext()) { int m; m = (int)(int)e.Current; Console.WriteLine(m); } } finally { if (e != null && e is IDisposable) { ((IDisposable)e).Dispose(); } } }
  14. 14. @davidwengier Lambdas public class C { public void M() { Action<string> act = x => Console.WriteLine(x); act(“hello”); } }
  15. 15. @davidwengier Lambdas public class C { public void M() { Action<string> act = _act; act(“hello”); } private void _act(string x) { Console.WriteLine(x); } }
  16. 16. @davidwengier Lambdas public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“hello”); } private class ActHelper { internal void act(string x) { Console.WriteLine(x); } } }
  17. 17. @davidwengier Lambdas public class C { public void M() { if (ActHelper.Instance._act == null) { ActHelper.Instance._act = new Action<string>(ActHelper.Instance.act); } Action<string> act = ActHelper.Instance._act; act(“hello”); } private sealed class ActHelper { public static readonly ActHelper Instance = new ActHelper(); public static Action<string> _act; internal void act(string x) { Console.WriteLine(x); } } }
  18. 18. @davidwengier public class C { public void M() { Action<string> act = x => Console.WriteLine(x); act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { internal void act(string x) { Console.WriteLine(x); } } }
  19. 19. @davidwengier public class C { public void M() { string y = “ World”; Action<string> act = x => Console.WriteLine(x + y); act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { internal void act(string x) { Console.WriteLine(x + y); } } } public class C { public void M() { ActHelper c = new ActHelper(); Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } } public class C { public void M() { ActHelper c = new ActHelper(); c.y = “ World”; Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } }
  20. 20. @davidwengier public class C { public void M() { string y = “ World”; Action<string> act = x => Console.WriteLine(x + y); y = “ Fish”; act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); c.y = “ World”; Action<string> act = c.act; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } }
  21. 21. @davidwengier public class C { public void M() { string y = “ World”; Action<string> act = x => Console.WriteLine(x + y); y = “ Fish”; act(“Hello”); } } public class C { public void M() { ActHelper c = new ActHelper(); c.y = “ World”; Action<string> act = c.act; c.y = “ Fish”; act(“Hello”); } private sealed class ActHelper { public string y; internal void act(string x) { Console.WriteLine(x + y); } } }
  22. 22. @davidwengier Foreach and lambdas List<Action> things = new List<Action>(); foreach (int m in values) { things.Add(() => Console.WriteLine(m)); }
  23. 23. @davidwengier Foreach and lambdas List<Action> things = new List<Action>(); { var e = values.GetEnumerator(); try { ActHelper c = new ActHelper(); while (e.MoveNext()) { c.m = (int)(int)e.Current; things.Add(new Action(c.act)); } } finally { if (e != null && e is IDisposable) ((IDisposable)e).Dispose(); } }
  24. 24. @davidwengier Foreach and lambdas (C# 5+) List<Action> things = new List<Action>(); { var e = values.GetEnumerator(); try { while (e.MoveNext()) { ActHelper c = new ActHelper(); c.m = (int)(int)e.Current; things.Add(new Action(c.act)); } } finally { if (e != null && e is IDisposable) ((IDisposable)e).Dispose(); } }
  25. 25. @davidwengier public class C { private int z; public void M() { string y = “ World”; Action<string> act = x => Console.Write(x + y + z); act(“Hello”); } } public class C { private int z; public void M() { ActHelper c = new ActHelper(); c.y = “ World”; c._this = this; c.act(“Hello”); } private sealed class ActHelper { public C _this; public string y; internal void act(string x) { Console.Write(x + y + _this.z); } } }
  26. 26. @davidwengier yield foreach (int x in GetInts()) { Console.WriteLine(x); } public IEnumerable<int> GetInts() { yield return 1; yield return 2; yield return 3; yield return 4; yield return 5; }
  27. 27. @davidwengier yield using (IEnumerator<int> enumerator = this.GetInts().GetEnumerator()) { while (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } } public IEnumerable<int> GetInts() { return new GetIntsHelper(-2); }
  28. 28. @davidwengier yield private class GetIntsHelper : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator { private int _state; private int _current; private int _initialThreadId; int IEnumerator<int>.Current { get { return this._current; } } object IEnumerator.Current { get { return this._current; } } public GetIntsHelper(int initialState) { this._state = initialState; this._initialThreadId = Environment.CurrentManagedThreadId; } void IDisposable.Dispose() { }
  29. 29. @davidwengier yield IEnumerator<int> IEnumerable<int>.GetEnumerator() { GetIntsHelper result; if (this._state == -2 && this._initialThreadId == Environment.CurrentManagedThreadId) { this._state = 0; result = this; } else { result = new GetIntsHelper(0); } return result; }
  30. 30. @davidwengier yield bool IEnumerator.MoveNext() { switch (this._state) { case 0: this._state = -1; this._current = 1; this._state = 1; return true; case 1: this._state = -1; this._current = 2; this._state = 2; return true; case 2: this._state = -1; this._current = 3; this._state = 3; return true; case 3: this._state = -1; this._current = 4; this._state = 4; return true; case 4: this._state = -1; this._current = 5; this._state = 5; return true; case 5: this._state = -1; return false; default: return false;
  31. 31. @davidwengier Yield states -2 : GetEnumerator() hasn’t been called -1 : Running – Getting the next value 0 : Before – MoveNext() hasn’t been called 1- 4 : Suspended – Waiting for a MoveNext() call 5 : After – Finished.
  32. 32. @davidwengier yield public IEnumerable<int> GetInts() { foreach (int x in Enumerable.Range(1, 10)) { yield return x; } }
  33. 33. @davidwengier yield private IEnumerator<int> _wrap; void IDisposable.Dispose() { if (this._state == -3 || this._state == 1) { this._Finally(); } } private void _Finally() { this._state = -1; if (this._wrap != null) { this._wrap.Dispose(); } }
  34. 34. @davidwengier yield bool IEnumerator.MoveNext() { try { // ... Next slide } catch { this.Dispose(); throw; } }
  35. 35. @davidwengier yield if (this._state == 0) { this._state = -1; this._wrap = Enumerable.Range(1, 10).GetEnumerator(); this._state = -3; } else { if (this._state != 1) return false; this._state = -3; } if (this._wrap.MoveNext()) { this._current = (int)this._wrap.Current; this._state = 1; return true; } else { this._Finally(); this._wrap = null; return false; }
  36. 36. @davidwengier Yield states -3 : Running – Getting the next value -2 : GetEnumerator() hasn’t been called -1 : Running – Getting the range enumerator 0 : Before – MoveNext() hasn’t been called 1 : Suspended (and After) – Waiting for a MoveNext() call
  37. 37. @davidwengier Captain planet private int _min; public void M() { int max = 5; foreach (int x in GetInts(max)) { Console.WriteLine(x); } } public IEnumerable<int> GetInts(int max) { yield return 1; foreach (int x in Enumerable.Range(this._min, max).OrderBy(i => i * this._min + max)) { yield return x; } } ???
  38. 38. @davidwengier Want to know more? • Roslyn source code • Your favourite decompiler • http://sharplab.io
  39. 39. @davidwengier Thank you! Questions? Comments? Quemments? @davidwengier

×