Slice with lambda: add C# exercise projects and export
- Add SliceWithLambda.slnx + csproj scaffolding for ideas/slice-with-lambda/ exercise/csharp (examples project + xUnit solution/test project) - Add exercises/slice-with-lambda (C# version of the prefactored-longrange exercise with Buyers and SliceWithLambda projects) - Add export/slice-with-lambda (nested git repo with exercise export) - Ignore bin/ and obj/ build output at repo root
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
// Example 3 solution — Ice cream shop demo of Slice with Lambda (C#), after
|
||||
//
|
||||
// Lambda extracted (step 1), slid to the top (step 2), method extracted
|
||||
// below the guard (step 3). The constructor now takes the lambda directly,
|
||||
// so tests construct with new IceCreamShop(() => 30).
|
||||
//
|
||||
// Condensed mechanics: https://sammancoaching.org/refactorings/slice.html
|
||||
// (where that page says mock, we use a lambda instead).
|
||||
|
||||
using System;
|
||||
|
||||
public enum Warmth
|
||||
{
|
||||
Cold,
|
||||
Warm
|
||||
}
|
||||
|
||||
public enum ThawAmount
|
||||
{
|
||||
None,
|
||||
Medium,
|
||||
Low
|
||||
}
|
||||
|
||||
public class Thermometer
|
||||
{
|
||||
private readonly Random _rng = new Random(); // stand-in for the hardware
|
||||
|
||||
public byte Read()
|
||||
{
|
||||
return (byte)_rng.Next(50); // raw sensor value
|
||||
}
|
||||
}
|
||||
|
||||
public class IceCreamShop
|
||||
{
|
||||
private readonly Func<byte> _readTemperature; // the thermometer, as a lambda
|
||||
private bool _thawedToday; // event-style client state
|
||||
|
||||
public IceCreamShop(Func<byte> readTemperature)
|
||||
{
|
||||
_readTemperature = readTemperature;
|
||||
}
|
||||
|
||||
public ThawAmount ThawStock()
|
||||
{
|
||||
Func<byte> readTemperature = () => _readTemperature(); // lambda at the top
|
||||
return ThawStockTail(readTemperature); // pass the lambda on
|
||||
}
|
||||
|
||||
private ThawAmount ThawStockTail(Func<byte> readTemperature)
|
||||
{
|
||||
if (_thawedToday) // guard: client state, stays
|
||||
{
|
||||
return ThawAmount.None;
|
||||
}
|
||||
|
||||
_thawedToday = true; // set only after thawing
|
||||
byte temperature = readTemperature(); // middle: the stubbed lambda
|
||||
Warmth warmth = ToWarmth(temperature);
|
||||
if (warmth == Warmth.Warm) // tail: complex behaviour below
|
||||
{ // the extraction point
|
||||
return ThawAmount.Medium;
|
||||
}
|
||||
return ThawAmount.Low;
|
||||
}
|
||||
|
||||
private static Warmth ToWarmth(byte temperature)
|
||||
{
|
||||
return temperature > 25 ? Warmth.Warm : Warmth.Cold;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Example 1 solution — Metaphor-free demo of Slice with Lambda (C#), after
|
||||
//
|
||||
// Lambda extracted (step 1), slid to the top (step 2), method extracted
|
||||
// below the guard (step 3), overload seam added (step 3b), b inlined
|
||||
// (final cleanup).
|
||||
//
|
||||
// Condensed mechanics: https://sammancoaching.org/refactorings/slice.html
|
||||
// (where that page says mock, we use a lambda instead).
|
||||
|
||||
using System;
|
||||
|
||||
public class Calculator
|
||||
{
|
||||
private readonly SomeDependency _someDependency;
|
||||
|
||||
public Calculator(SomeDependency someDependency)
|
||||
{
|
||||
_someDependency = someDependency;
|
||||
}
|
||||
|
||||
public int Calculate(int a) // overload: callers unchanged
|
||||
{
|
||||
return Calculate(a, a =>
|
||||
_someDependency.mightThrowWhenPreconditionNotSatisfied(a));
|
||||
} // the real λ, baked into the head
|
||||
|
||||
public int Calculate(int a, Func<int, int> readB) // the seam: λ is a parameter
|
||||
{
|
||||
if (a < 0) return 0; // guard clause: stays
|
||||
return CalculateTail(a, readB);
|
||||
}
|
||||
|
||||
private int CalculateTail(int a, Func<int, int> readB)
|
||||
{
|
||||
int c = a + readB(a); // b inlined
|
||||
return c * 2;
|
||||
}
|
||||
}
|
||||
|
||||
public class SomeDependency
|
||||
{
|
||||
private readonly Random _rng = new Random(); // stand-in for unpredictable computation
|
||||
|
||||
public int mightThrowWhenPreconditionNotSatisfied(int a)
|
||||
{
|
||||
if (a > 99)
|
||||
{
|
||||
throw new InvalidOperationException("precondition not satisfied");
|
||||
}
|
||||
return _rng.Next(100);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,72 @@
|
||||
// Example 2 solution — Weather Station domain demo of Slice with Lambda (C#), after
|
||||
//
|
||||
// Lambda extracted (step 1), slid to the top (step 2), method extracted
|
||||
// below the guard (step 3). The constructor now takes the lambda directly,
|
||||
// so tests construct with new SprinklerController(() => 200).
|
||||
//
|
||||
// Condensed mechanics: https://sammancoaching.org/refactorings/slice.html
|
||||
// (where that page says mock, we use a lambda instead).
|
||||
|
||||
using System;
|
||||
|
||||
public enum SunExposure
|
||||
{
|
||||
Shady,
|
||||
Sunny
|
||||
}
|
||||
|
||||
public enum WateringDuration
|
||||
{
|
||||
None,
|
||||
Medium,
|
||||
Short
|
||||
}
|
||||
|
||||
public class LightSensor
|
||||
{
|
||||
private readonly Random _rng = new Random(); // stand-in for hardware noise
|
||||
|
||||
public byte Read()
|
||||
{
|
||||
return (byte)_rng.Next(256);
|
||||
}
|
||||
}
|
||||
|
||||
public class SprinklerController
|
||||
{
|
||||
private readonly Func<byte> _readLight; // the sensor, as a lambda
|
||||
private bool _wateredToday; // event-style client state
|
||||
|
||||
public SprinklerController(Func<byte> readLight)
|
||||
{
|
||||
_readLight = readLight;
|
||||
}
|
||||
|
||||
public WateringDuration ScheduleWatering()
|
||||
{
|
||||
Func<byte> readLight = () => _readLight(); // lambda definition at the top
|
||||
return ScheduleWateringTail(readLight); // pass the lambda on
|
||||
}
|
||||
|
||||
private WateringDuration ScheduleWateringTail(Func<byte> readLight)
|
||||
{
|
||||
if (_wateredToday) // guard: client state, stays
|
||||
{
|
||||
return WateringDuration.None;
|
||||
}
|
||||
|
||||
_wateredToday = true; // set only after watering
|
||||
byte reading = readLight(); // middle: the stubbed lambda
|
||||
SunExposure exposure = ToSunExposure(reading);
|
||||
if (exposure == SunExposure.Sunny) // tail: complex behaviour below
|
||||
{ // the extraction point
|
||||
return WateringDuration.Medium;
|
||||
}
|
||||
return WateringDuration.Short;
|
||||
}
|
||||
|
||||
private static SunExposure ToSunExposure(byte reading)
|
||||
{
|
||||
return reading > 128 ? SunExposure.Sunny : SunExposure.Shady;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user