C# でローカル変数の再代入を禁止したいとき
とりあえずみんな一回 let 句使ってコード書いてみるべき.
var seq = from _ in Enumerable.Repeat(1, 1) let x = 1000 let xs = new List<int>{x} let y = Math.PI / 2.0 let z = "hauhau" select _;
var pixelsQuery = from y in Enumerable.Range(0, screenHeight) let recenterY = -(y - (screenHeight / 2.0)) / (2.0 * screenHeight) select from x in Enumerable.Range(0, screenWidth) let recenterX = (x - (screenWidth / 2.0)) / (2.0 * screenWidth) let point = Vector.Norm(Vector.Plus(scene.Camera.Forward, Vector.Plus(Vector.Times(recenterX, scene.Camera.Right), Vector.Times(recenterY, scene.Camera.Up)))) let ray = new Ray { Start = scene.Camera.Pos, Dir = point } let computeTraceRay = (Func<Func<TraceRayArgs, Color>, Func<TraceRayArgs, Color>>) (f => traceRayArgs => (from isect in from thing in traceRayArgs.Scene.Things select thing.Intersect(traceRayArgs.Ray) where isect != null orderby isect.Dist let d = isect.Ray.Dir let pos = Vector.Plus(Vector.Times(isect.Dist, isect.Ray.Dir), isect.Ray.Start) let normal = isect.Thing.Normal(pos) let reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal)) let naturalColors = from light in traceRayArgs.Scene.Lights let ldis = Vector.Minus(light.Pos, pos) let livec = Vector.Norm(ldis) let testRay = new Ray { Start = pos, Dir = livec } let testIsects = from inter in from thing in traceRayArgs.Scene.Things select thing.Intersect(testRay) where inter != null orderby inter.Dist select inter let testIsect = testIsects.FirstOrDefault() let neatIsect = testIsect == null ? 0 : testIsect.Dist let isInShadow = !((neatIsect > Vector.Mag(ldis)) || (neatIsect == 0)) where !isInShadow let illum = Vector.Dot(livec, normal) let lcolor = illum > 0 ? Color.Times(illum, light.Color) : Color.Make(0, 0, 0) let specular = Vector.Dot(livec, Vector.Norm(reflectDir)) let scolor = specular > 0 ? Color.Times(Math.Pow(specular, isect.Thing.Surface.Roughness), light.Color) : Color.Make(0, 0, 0) select Color.Plus(Color.Times(isect.Thing.Surface.Diffuse(pos), lcolor), Color.Times(isect.Thing.Surface.Specular(pos), scolor)) let reflectPos = Vector.Plus(pos, Vector.Times(.001, reflectDir)) let reflectColor = traceRayArgs.Depth >= MaxDepth ? Color.Make(.5, .5, .5) : Color.Times(isect.Thing.Surface.Reflect(reflectPos), f(new TraceRayArgs(new Ray { Start = reflectPos, Dir = reflectDir }, traceRayArgs.Scene, traceRayArgs.Depth + 1))) select naturalColors.Aggregate(reflectColor, (color, natColor) => Color.Plus(color, natColor))) .DefaultIfEmpty(Color.Background).First()) let traceRay = Y(computeTraceRay) select new { X = x, Y = y, Color = traceRay(new TraceRayArgs(ray, scene, 0)) }; foreach (var row in pixelsQuery) foreach (var pixel in row) setPixel(pixel.X, pixel.Y, pixel.Color.ToDrawingColor());
(追記)
そういえば『C# 3.0 と let キーワード - NyaRuRuの日記』でも色々サンプル書いていた.
FizzBuzz
var f2 = from x in Enumerable.Range(1, 100) let a = x % 3 == 0 ? "Fizz" : "" let b = x % 5 == 0 ? "Buzz" : "" let c = (x % 3 != 0 && x % 5 != 0) ? x.ToString() : "" select a + b + c;
今年の1月1日から12月31日までを列挙
var cal = from month in Enumerable.Range(1, 12) let year = DateTime.Today.Year let numDays = DateTime.DaysInMonth(year, month) from day in Enumerable.Range(1, numDays) select new DateTime(year, month, day);
2000年から2009年までの13日の金曜日は?
var ft13 = from year in Enumerable.Range(2000, 10) let daysInThisYear = from month in Enumerable.Range(1, 12) let numDays = DateTime.DaysInMonth(year, month) from day in Enumerable.Range(1, numDays) select new DateTime(year, month, day) from date in daysInThisYear where date.Day == 13 && date.DayOfWeek == DayOfWeek.Friday select date;
2000年から2009年までの各年の日曜日の数
var mysundays = from year in Enumerable.Range(2000, 10) let daysInThisYear = from month in Enumerable.Range(1, 12) let numDays = DateTime.DaysInMonth(year, month) from day in Enumerable.Range(1, numDays) select new DateTime(year, month, day) let sundaysInThisYear = from date in daysInThisYear where date.DayOfWeek == DayOfWeek.Sunday select date select new { Year = year, SundayCount = sundaysInThisYear.Count() };