The C# example below comes from a refactoring of the controller here. This is based on how Jon Skeet defines a closure on page 151 of his first edition of "C# in Depth." He makes a distinction between outer variables such as firstInteger and secondInteger which exist in the same method as the closure and are merely used by it, and a captured variable such as captured which gets effected by the closure. The x name for the ThreadStart comes from Mr. Skeet, so don't blame me for the odd variable name. :P It is important to note that if one does not run the line reading x(); that the magic will never happen and captured's shape will remain unchanged. This approach allowed me to drop that silly StatusQuoSustainer method from the controller as I no longer need a default for my case statement! Yay! As you can see, when x(); is run it considers captured and then effects the captured variable based upon its contents with the outer variables.
using System;
using System.Threading;
namespace DelegateExample.Controllers
{
public class CalculationController : BaseController
{
public RenderJsonResult Go(string act, string one, string two)
{
string captured = act;
Int32 firstInteger = Convert.ToInt32(one);
Int32 secondInteger = Convert.ToInt32(two);
ThreadStart x = delegate
{
switch (captured)
{
case "add":
captured = Adder(firstInteger, secondInteger);
break;
case "multiply":
captured = Multiplier(firstInteger, secondInteger);
break;
case "power":
captured = Raiser(firstInteger, secondInteger);
break;
}
};
x();
var result = new { calulation = captured };
return RenderJson(result);
}
private string Adder(Int32 firstInteger, Int32 secondInteger)
{
return (firstInteger + secondInteger).ToString();
}
private string Multiplier(Int32 firstInteger, Int32 secondInteger)
{
return (firstInteger * secondInteger).ToString();
}
private string Raiser(Int32 firstInteger, Int32 secondInteger)
{
Int32 growingInteger = firstInteger;
Int32 counterIntger = 1;
while (counterIntger < secondInteger)
{
growingInteger = growingInteger * firstInteger;
counterIntger++;
}
return growingInteger.ToString();
}
}
}
The next example is also of C#, illuminates the = () => operator, and comes from "C# 4.0 in a Nutshell: The Definitive Reference" by Joseph Albahari and Ben Albahari. The operator signifies a closure per page 132. I have modified the controller here to make this code. These closures allow us to pull the inbound values for a Func out of the Func's signature and instead set them on the other side of the operator. So instead of asserting that a Func<Int32,Int32,string> is equal to a method we may instead assert that a Func<string> is equal to a method while clarifying that the method takes two Int32 types for inbound parameters. Not only is this a little bit easier to read, but we are now no longer in a straightjacket in terms of restraints for inbound parameters. We may use a method of any manner of signature so long as the method returns the string. See how I was able to clean up StatusQuoSustainer. I removed an arbitrary variable once I was able to do so.
using System;
namespace DelegateExample.Controllers
{
public class CalculationController : BaseController
{
public RenderJsonResult Go(string act, string one, string two)
{
Int32 firstInteger = Convert.ToInt32(one);
Int32 secondInteger = Convert.ToInt32(two);
Func<string> mathDelegate;
switch(act)
{
case "add":
mathDelegate = () => Adder(firstInteger, secondInteger);
break;
case "multiply":
mathDelegate = () => Multiplier(firstInteger, secondInteger);
break;
case "power":
mathDelegate = () => Raiser(firstInteger, secondInteger);
break;
default:
mathDelegate = () => StatusQuoSustainer(firstInteger);
break;
}
string thirdValue = mathDelegate();
var result = new { calulation = thirdValue };
return RenderJson(result);
}
private string Adder(Int32 firstInteger, Int32 secondInteger)
{
return (firstInteger + secondInteger).ToString();
}
private string Multiplier(Int32 firstInteger, Int32 secondInteger)
{
return (firstInteger * secondInteger).ToString();
}
private string Raiser(Int32 firstInteger, Int32 secondInteger)
{
Int32 growingInteger = firstInteger;
Int32 counterIntger = 1;
while (counterIntger < secondInteger)
{
growingInteger = growingInteger * firstInteger;
counterIntger++;
}
return growingInteger.ToString();
}
private string StatusQuoSustainer(Int32 loneInteger)
{
return loneInteger.ToString();
}
}
}
The final example comes from Derek Greer and is of jQuery. What follows is a revision of the TryToCalculate() method here. I broke the sanity checking up into two hunks, one inside of another, to illustrate that one may create a closure and prep it for use before actually using it downstream in code. In crafting this last example I realized that I've misspelled growingInteger as growingIntger in all of my previous examples. Whatever.
function TryToCalculate() {
var checky = "";
var checkact = "" + $('input[name=act]:checked').val();
checky = checky + checkact;
if (checky.indexOf("undefined") < 0) {
var calculationRules = function (act) {
return function (firstInteger, secondInteger) {
if (act == "add") return firstInteger + secondInteger;
if (act == "multiply") return firstInteger * secondInteger;
var growingInteger = firstInteger;
var counterInteger = 1;
while (counterInteger < secondInteger)
{
growingInteger = growingInteger * firstInteger;
counterInteger++;
}
return growingInteger;
};
};
closure = calculationRules(checky);
var checkone = "" + $('input[name=one]:checked').val();
var checktwo = "" + $('input[name=two]:checked').val();
checky = checky + checkone + checktwo;
if (checky.indexOf("undefined") < 0) {
var castingOne = parseInt(checkone);
var castingTwo = parseInt(checktwo);
document.getElementById('equals').innerHTML = closure(castingOne,castingTwo);
}
}
}
No comments:
Post a Comment