Introduction
using Lambda expressions, we often encounter some typical application scenarios, and scenarios extracted from common application mode can be described as application mode. these patterns may be incomplete is the new model, and some reference from JavaScript, design patterns, but at least I have seen some people are marked with a name tag. Whether good or bad name, I decided to give these modes are named, at least these names are descriptive. I will give both the availability of these models, a strong part and the dangerous part. Early first note: Most of these patterns are very powerful, but there may be something in the code to introduce a potential Bug. Therefore, caution.
directory navigation
- callback mode (Callback Pattern)
- function as a return value (Returning Functions)
- custom functions (Self-Defining Functions)
- immediately call the function expression (Immediately-Invoked Function Expression)
- immediate object initialization (Immediate Object Initialization)
- initialization time branch (Init-Time Branching)
- lazy loading (Lazy Loading)
- attributes and multi-state mode (Lambda Property Polymorphism Pattern)
- function dictionary mode (Function Dictionary Pattern)
- functional characteristics (Functional Attribute Pattern)
- avoid circular references (Avoiding cyclic references)
callback mode (Callback Pattern)
commonplace. In fact,. NET, the first version has supported callback mode, but the form is different. By now the closure of Lambda expressions and local variables capture, this feature becomes more and more interesting. Now our code can be similar to:
1 void CreateTextBox()
2 {
3 var tb = new TextBox();
4 tb.IsReadOnly = true;
5 tb.Text = "Please wait ...";
6 DoSomeStuff(() =>
7 {
8 tb.Text = string.Empty;
9 tb.IsReadOnly = false;
10 });
11 }
12
13 void DoSomeStuff(Action callback)
14 {
15 // Do some stuff - asynchronous would be helpful ...
16 callback();
17 }
for JavaScript developers, this model has nothing new to it. And usually we have a lot of use in this mode, because it is very useful. For example, we can use the time as a parameter to handle processor-related events such as AJAX. In LINQ, we also use this mode, such as in LINQ Where will query each iteration callback function. These are just some of the callback mode can be useful to illustrate simple example. In. NET is usually recommended to use an event callback mechanism. There are two reasons, first, has provided a special keyword and type modes (there are two parameters, one is the sender, a number of event parameters, while the sender is usually object type, and the event parameter is usually inherited from EventArgs), At the same time by using the + = and - + operator, but also provides the opportunity to invoke multiple methods.
function as a return value (Returning Functions)
function as common as, Lambda expressions can return a function pointer (delegate instance). This means that we can use to create a Lambda expressions and returns another Lambda expressions. This behavior is in many scenarios are very useful. Let's look at the following example:
1 Func<string, string> SayMyName(string language)
2 {
3 switch (language.ToLower())
4 {
5 case "fr":
6 return name =>
7 {
8 return "Je m'appelle " + name + ".";
9 };
10 case "de":
11 return name =>
12 {
13 return "Mein Name ist " + name + ".";
14 };
15 default:
16 return name =>
17 {
18 return "My name is " + name + ".";
19 };
20 }
21 }
22
23 void Main()
24 {
25 var lang = "de";
26 //Get language - e.g. by current OS settings
27 var smn = SayMyName(lang);
28 var name = Console.ReadLine();
29 var sentence = smn(name);
30 Console.WriteLine(sentence);
31 }
this code can be written more succinctly. If the requested type of language is not found, we can throw an exception, in order to avoid returning a default value. Of course, for demonstration purposes, this example shows is similar to a function factory. Another way is to introduce Hashtable, or better yet, Dictionary
1 static class Translations
2 {
3 static readonly Dictionary<string, Func<string, string>> smnFunctions
4 = new Dictionary<string, Func<string, string>>();
5
6 static Translations()
7 {
8 smnFunctions.Add("fr", name => "Je m'appelle " + name + ".");
9 smnFunctions.Add("de", name => "Mein Name ist " + name + ".");
10 smnFunctions.Add("en", name => "My name is " + name + ".");
11 }
12
13 public static Func<string, string> GetSayMyName(string language)
14 {
15 //Check if the language is available has been omitted on purpose
16 return smnFunctions[language];
17 }
18 }
19
20 // Now it is sufficient to call Translations.GetSayMyName("de")
21 // to get the function with the German translation.
While this may seem a bit over-designed suspected, but after all, this approach can easily be extended and can be applied to many scenarios. If the combination of reflection together, can make the program more flexible, easier to maintain, and more robust. The following shows how this pattern work:
< / span>
custom functions (Self-Defining Functions)
in JavaScript, a custom function is an extremely common design techniques, and in some code can get better performance. The main idea is that this model will be a function as a property, and this property can be very easy to change other functions.
1 class SomeClass
2 {
3 public Func<int> NextPrime
4 {
5 get;
6 private set;
7 }
8
9 int prime;
10
11 public SomeClass()
12 {
13 NextPrime = () =>
14 {
15 prime = 2;
16
17 NextPrime = () =>
18 {
19 //Algorithm to determine next - starting at prime
20 //Set prime
21 return prime;
22 };
23
24 return prime;
25 };
26 }
27 }
what to do here? First we got the first prime number is 2. It is not important, is that we can adjust the algorithm to exclude all even. This is to some extent will accelerate our algorithm, but we are still setting 2 is a prime number starting point. We do not need to see whether the call NextPrime () function, because according to the definition within the function directly returns 2. In this way, we save resources and to optimize algorithms.
Similarly, we can also see the performance will be better to do so. Let us look at the following example:
1 Action<int> loopBody = i => {
2 if(i == 1000)
3 loopBody = /* set to the body for the rest of the operations */;
4
5 /* body for the first 1000 iterations */
6 };
7
8 for(int j = 0; j < 10000000; j++)
9 loopBody(j);
Here we have two distinct areas, one is a former 1000 iterations, and the other is the rest of the 9,999,000 iterations. Usually we need a condition to distinguish these two cases. In most cases will cause unnecessary overhead, which is why we want to use a custom function in the implementation of a short code later changed its own.
immediately call the function expression (Immediately-Invoked Function Expression)
In JavaScript, immediately call the function expression (abbreviated as IIFE) is a very common usage. The reason is not using JavaScript and C # in a similar way to organize braces variable scope, but according to the function block to division. Therefore, the variable will pollute the global object, usually a window object, which is not what we expect results.
solution is very simple, although braces are not given scope, but the function is given, because the in vivo function of the variables defined inside a function scope are limited. The JavaScript-users often think that if only for direct execution of those functions for which the statement specifies the name of the variable and then execute it becomes a waste. Another reason is that these functions need only be performed once.
in C #, we can simply write the following function to achieve the same functionality. Here we also got a new scope, but this is not our main goal, because if you need it, wherever we can create a new scope.
1 (() => {
2 // Do Something here!
3 })();
code looks very simple. If we need to pass some parameters, you need to specify the type of the parameter.
1 ((string s, int no) => {
2 // Do Something here!
3 })("Example", 8);
seem to write so many lines of code did not give us any good. Nevertheless, we can use this mode and async keyword combination.
1 await (async (string s, int no) => {
2 // Do Something here async using Tasks!
3 })("Example", 8);
4
5 //Continue here after the task has been finished
Thus, the usage is similar to the asynchronous wrapper is formed.
immediate object initialization (Immediate Object Initialization)
this pattern contains the reasons in this article which is anonymous object this function is too strong, and its not only contain simple types, but also contains Lambda expressions.
1 //Create anonymous object
2 var person = new
3 {
4 Name = "Florian",
5 Age = 28,
6 Ask = (string question) =>
7 {
8 Console.WriteLine("The answer to `" + question + "` is certainly 42!");
9 }
10 };
11
12 //Execute function
13 person.Ask("Why are you doing this?");
If you run the above code, you may see an exception (at least I saw). The reason is, Lambda expressions can not be assigned directly to an anonymous object. If you feel incredible, the feeling that we are the same. Fortunately, the compiler tells us "Dude, I do not know what I should Lambda expressions created for this kind of delegate type." If so, we will help the compiler.
1 var person = new
2 {
3 Name = "Florian",
4 Age = 28,
5 Ask = (Action<string>)((string question) =>
6 {
7 Console.WriteLine("The answer to `" + question + "` is certainly 42!");
8 })
9 };
a question arises: where the function (Ask method) What is the scope? The answer is, it will survive in creating this anonymous object class, or if it is caught using a variable exists in its own scope. Therefore, the compiler still creates an anonymous object, and then point to the created Lambda expressions assigned delegate object attributes Ask.
Note: When we want to set an anonymous object Lambda expressions directly access any of the properties of anonymous objects, then try to avoid using this mode. The reason is: C # compiler requires each object before it is used needs to be declared. In this case, the use of affirmation in a statement later, but the compiler is how to know? From the point of view of the compiler, in this case with the use of declarations occur simultaneously, so the reference person is not to be declared.
There is a way that can help us solve this problem (in fact, there are many ways, but in my opinion, this approach is the most elegant).
1 dynamic person = null;
2 person = new
3 {
4 Name = "Florian",
5 Age = 28,
6 Ask = (Action<string>)((string question) =>
7 {
8 Console.WriteLine("The answer to `" + question + "` is certainly 42! My age is " + person.Age + ".");
9 })
10 };
11
12 //Execute function
13 person.Ask("Why are you doing this?");
see, now we have to declare it. Of course, we can also directly person declared as object types, but this way we can use reflection to access anonymous object's properties. Here we rely on the DLR (Dynamic Language Runtime) to achieve, which should be the best way of packing up. Now, this code looks very JavaScript Fan children, but in fact I do not know what use this thing in the end.
initialization time branch (Init-Time Branching)
this model with a custom function modes are closely related. The only difference is that the function is no longer define its own, but through other function definitions. Of course, other functions may not through the traditional way to define, but by covering properties.
This pattern is often called loading branch (Load-Time Branching), is essentially an optimization mode. This mode is used to avoid the constant switch-case and if-else control structure such use. So in a way it can be said that this model for some constant establishes a link between code branches.
1 public Action AutoSave { get; private set; }
2
3 public void ReadSettings(Settings settings)
4 {
5 /* Read some settings of the user */
6
7 if (settings.EnableAutoSave)
8 AutoSave = () => { /* Perform Auto Save */ };
9 else
10 AutoSave = () => { }; //Just do nothing!
11 }
here we did two things. First, we have a method to read the user setup information. If we find that for the auto-save feature has been opened, we will save the code assigned to the property. Otherwise, we just specify an empty method. Then, we can always call AutoSave property in the operation. And after that we no longer need to check the user to set the information. We do not need this specific settings saved to a boolean variable, because the dynamic response function has been set up.
you might say that this is not much of a performance improvement, but this is just a simple example. In some complex code, this method can really save a lot of time, especially in a large loop, call a method that dynamically set.
same time, this code may be easier to maintain, and very easy to read. In eliminating a lot of unnecessary control process, we are able to direct focus: Call AutoSave function.
In JavaScript, this model is often used to detect the browser's feature set. Detects browser capabilities are a nightmare for any website is the same, and in the realization of this model becomes very useful. Similarly jQuery also used the same pattern to detect the correct object in order to use AJAX functionality. Once it identifies browsers support XMLHttpRequest, is because the browser does not change during the execution of the script, so no need to consider the handle ActiveX object.
lazy loading (Lazy Loading)
we want to create an object, it can perform some delay in loading operation. That is, although the object has been properly initialized, but we did not load all the required resources. One reason is to avoid getting to the data caused by a large number of IO operations. Meanwhile, we also want to use in the preparation of the data, the data is up to date as possible. There are many ways to achieve this function, and in the Entity Framework uses highly efficient LINQ to solve lazy loading situations. Wherein, IQueryable
scenario we want, we need to distinguish between two situations. First we check, and the subsequent operation will result in the already acquired on.
1 class LazyLoad
2 {
3 public LazyLoad()
4 {
5 Search = query =>
6 {
7 var source = Database.SearchQuery(query);
8
9 Search = subquery =>
10 {
11 var filtered = source.Filter(subquery);
12
13 foreach (var result in filtered)
14 yield return result;
15 };
16
17 foreach (var result in source)
18 yield return result;
19 };
20 }
21
22 public Func<string, IEnumerable<ResultObject>> Search { get; private set; }
23 }
Well, here we basically need to set up two different methods. A pull data from a database, and the other is obtained from the data to be filtered. Of course, you might be thinking we can create another method in the class to set these acts, or use other methods may be more effective.
attribute multi-state mode (Lambda Property Polymorphism Pattern)
Lambda expressions can be used to implement polymorphism (override), without the need to use keywords such as abstract and virtual.
1 class MyBaseClass
2 {
3 public Action SomeAction { get; protected set; }
4
5 public MyBaseClass()
6 {
7 SomeAction = () =>
8 {
9 //Do something!
10 };
11 }
12 }
here nothing special. We created a class through an attribute to expose a function. It's a bit like JavaScript style. Interesting place lies not only in this class can control and change the function attributes, and can change its derived classes.
1 class MyInheritedClass : MyBaseClass
2 {
3 public MyInheritedClass
4 {
5 SomeAction = () => {
6 //Do something different!
7 };
8 }
9 }
look! Here we are actually able to change this property is entirely dependent on the protected application. The disadvantage of this approach is that we can not directly access the parent class implementation. Here we lose the power of the base, as in base attributes have the same value. If you really need such a feature, I recommend using the following kind of "model":
1 class MyBaseClass
2 {
3 public Action SomeAction { get; private set; }
4
5 Stack<Action> previousActions;
6
7 protected void AddSomeAction(Action newMethod)
8 {
9 previousActions.Push(SomeAction);
10 SomeAction = newMethod;
11 }
12
13 protected void RemoveSomeAction()
14 {
15 if (previousActions.Count == 0)
16 return;
17
18 SomeAction = previousActions.Pop();
19 }
20
21 public MyBaseClass()
22 {
23 previousActions = new Stack<Action>();
24
25 SomeAction = () =>
26 {
27 //Do something!
28 };
29 }
30 }
Thus, in a subclass can only call AddSomeAction () to override the currently set approach. This method will be placed directly into a stack, which allows us to record the previous state.
I give this pattern from the name attribute is multi-state mode Lambda (Lambda Property Polymorphism Pattern). It describes the function package for the possibility of the property, and then in the derived class can override the parent class attributes. The above code is just a stack of extra features, does not change this pattern goal.
Why do we need this model? Frankly, there are a variety of reasons. The first is because we can do it. But beware, in fact, if we want to use a number of different properties, this pattern will become more flexible. "Polymorphic" the word will have a whole new meaning, but that is another mode again. So here I mainly want to emphasize this model can achieve some of the functions previously considered impossible.
For example: You want to override a static method (not recommended, but perhaps doing so is able to solve your problem most elegant way). Well, inheritance is impossible to change a static method. The reason is simple: inherit only applies to instances of classes and static methods has not been bound to the instance of the class. Static methods for all instances of a class are the same. Here also contains a warning, following this pattern may not be not achieved the results you want, so be sure to be clear why you want to use it.
1 void Main()
2 {
3 var mother = HotDaughter.Activator().Message;
4 //mother = "I am the mother"
5 var create = new HotDaughter();
6 var daughter = HotDaughter.Activator().Message;
7 //daughter = "I am the daughter"
8 }
9
10 class CoolMother
11 {
12 public static Func<CoolMother> Activator { get; protected set; }
13
14 //We are only doing this to avoid NULL references!
15 static CoolMother()
16 {
17 Activator = () => new CoolMother();
18 }
19
20 public CoolMother()
21 {
22 //Message of every mother
23 Message = "I am the mother";
24 }
25
26 public string Message { get; protected set; }
27 }
28
29 class HotDaughter : CoolMother
30 {
31 public HotDaughter()
32 {
33 //Once this constructor has been "touched" we set the Activator ...
34 Activator = () => new HotDaughter();
35 //Message of every daughter
36 Message = "I am the daughter";
37 }
38 }
This is a very simple example, and hope not to be misleading. If so used may cause things become more complicated, so I always say why do we need to avoid such use, but describes its feasibility. About Static polymorphism better solution is not always easy to implement, and requires a lot of code, so unless it really can help you solve practical problems, rather than make you more headaches.
function dictionary mode (Function Dictionary Pattern)
before I have introduced this model, but have not specified the name, it is the function of the dictionary mode (Function Dictionary Pattern). The basic components of this model include: a hash table or dictionary to contain a number of key-value pair, a key may be of any type, the value is a function of certain types. This model also specifies a special dictionary constructed. In this mode it is necessary, it can use a switch-case to achieve the same purpose.
1 public Action GetFinalizer(string input)
2 {
3 switch
4 {
5 case "random":
6 return () => { /* ... */ };
7 case "dynamic":
8 return () => { /* ... */ };
9 default:
10 return () => { /* ... */ };
11 }
12 }
the above code, we need a dictionary type do? Of course. We can do this:
1 Dictionary<string, Action> finalizers;
2
3 public void BuildFinalizers()
4 {
5 finalizers = new Dictionary<string, Action>();
6 finalizers.Add("random", () => { /* ... */ });
7 finalizers.Add("dynamic", () => { /* ... */ });
8 }
9
10 public Action GetFinalizer(string input)
11 {
12 if(finalizers.ContainsKey(input))
13 return finalizers[input];
14
15 return () => { /* ... */ };
16 }
Note, however, this model is used here did not bring any benefit. In fact, this mode is less efficient and requires more extra code. But we can do that through reflection is a function of the dictionary construction process automation. The same or not using switch-case statement, high efficiency, but the code more robust, maintainable. In fact, this operation is also very convenient, for example, we have a lot of code, we do not even know which way to add switch-case code block.
we look at a possible implementation. Normally I would recommend adding some conventions in the code to be able to get the dictionary keys. Of course, we can also choose the class name of a property, or directly using the name of the method to meet demand. In the following example, we select only a convention:
1 static Dictionary<string, Action> finalizers;
2
3 //The method should be called by a static constructor or something similar
4 //The only requirement is that we built
5 public static void BuildFinalizers()
6 {
7 finalizers = new Dictionary<string, Action>();
8
9 //Get all types of the current (= where the code is contained) assembly
10 var types = Assembly.GetExecutingAssembly().GetTypes();
11
12 foreach (var type in types)
13 {
14 //We check if the class is of a certain type
15 if (type.IsSubclassOf(typeof(MyMotherClass)))
16 {
17 //Get the constructor
18 var m = type.GetConstructor(Type.EmptyTypes);
19
20 //If there is an empty constructor invoke it
21 if (m != null)
22 {
23 var instance = m.Invoke(null) as MyMotherClass;
24 //Apply the convention to get the name - in this case just we pretend it is as simple as
25 var name = type.Name.Remove("Mother");
26 //Name could be different, but let's just pretend the method is named MyMethod
27 var method = instance.MyMethod;
28
29 finalizers.Add(name, method);
30 }
31 }
32 }
33 }
34
35 public Action GetFinalizer(string input)
36 {
37 if (finalizers.ContainsKey(input))
38 return finalizers[input];
39
40 return () => { /* ... */ };
41 }
now this code is not better yet. In fact, this model can save a lot of work. And the best thing is: it allows you to achieve a similar plug-in model, and make this feature applications across assemblies. Why do you say? For instance, we can scan the specified pattern library, and add it to your code. This way you can also add other libraries in the function to the current code.
1 //The start is the same
2
3 internal static void BuildInitialFinalizers()
4 {
5 finalizers = new Dictionary<string, Action>();
6 LoadPlugin(Assembly.GetExecutingAssembly());
7 }
8
9 public static void LoadPlugin(Assembly assembly)
10 {
11 //This line has changed
12 var types = assembly.GetTypes();
13
14 //The rest is identical! Perfectly refactored and obtained a new useful method
15 foreach (var type in types)
16 {
17 if (type.IsSubclassOf(typeof(MyMotherClass)))
18 {
19 var m = type.GetConstructor(Type.EmptyTypes);
20
21 if (m != null)
22 {
23 var instance = m.Invoke(null) as MyMotherClass;
24 var name = type.Name.Remove("Mother");
25 var method = instance.MyMethod;
26 finalizers.Add(name, method);
27 }
28 }
29 }
30 }
31
32 //The call is the same
Now we only need a point to specify the plug-in. Finally the path will be read from a library, trying to create an assembly object, and then call LoadPlugin () to load the assembly.
functional characteristics (Functional Attribute Pattern)
Attribute is the C # language in one of the best features. With Attribute, worked in C / C + + is not easy to achieve in the function of only a few in C # code that can be realized. This mode Attribute combined together with Lambda expressions. In the final, functional properties model (Functional Attribute Pattern) will increase Attribute application possibilities and productivity.
can say that will bind to Lambda expressions and Attribute together also quite helpful, because we no longer need to write specific classes. Let's look at an example to explain specifically what is meant.
1 class MyClass
2 {
3 public bool MyProperty
4 {
5 get;
6 set;
7 }
8 }
now for instances of this class, we want to be able, according to some characteristics of the area or scripting language to change this property. Then we want to be able to not write any extra code to change the conditions down value of the property. Of course, we still need some reflection. Also need some attribute to specify whether the attribute value can be changed by the user.
1 class MyClass
2 {
3 [NumberToBooleanConverter]
4 [StringToBooleanConverter]
5 public bool MyProperty
6 {
7 get;
8 set;
9 }
10 }
we define two converters. Although the use of a mark can be used for this attribute can be used by any changes. We use two to provide users with more possibilities. In this scenario, a user may actually use a string to set this value (to convert a string into a Boolean value) or by a number (such as 0 or 1).
then these converters how to achieve it? We look at the StringToBooleanConverterAttribute implementation.
1 public class StringToBooleanConverterAttribute : ValueConverterAttribute
2 {
3 public StringToBooleanConverterAttribute()
4 : base(typeof(string), v => {
5 var str = (v as string ?? string.Empty).ToLower();
6
7 if (str == "on")
8 return true;
9 else if (str == "off")
10 return false;
11
12 throw new Exception("The only valid input arguments are [ on, off ]. You entered " + str + ".");
13 })
14 {
15 /* Nothing here on purpose */
16 }
17 }
18
19 public abstract class ValueConverterAttribute : Attribute
20 {
21 public ValueConverterAttribute(Type expected, Func<object, object> converter)
22 {
23 Converter = converter;
24 Expected = expected;
25 }
26
27 public ValueConverterAttribute(Type expected)
28 {
29 Expected = expected;
30 }
31
32 public Func<Value, object> Converter { get; set; }
33
34 public object Convert(object argument)
35 {
36 return Converter.Invoke(argument);
37 }
38
39 public bool CanConvertFrom(object argument)
40 {
41 return Expected.IsInstanceOfType(argument);
42 }
43
44 public Type Expected
45 {
46 get;
47 set;
48 }
49
50 public string Type
51 {
52 get { return Expected.Name; }
53 }
54 }
Use this mode we got what good is it? If Attribute able to accept nonconstant expression as an argument (eg delegate, Lambda expressions, etc. are likely), then we get the benefits will be more. In this way, we only need to use Lambda expression to replace the abstract method, and then pass it to the parent class constructor.
you may say, this and abstract function than did nothing new, but the interesting part is that not the same as using a function to use, but as an attribute that can be set externally. This can be used for some dynamic code to rewrite some of the converters, although it has been instantiated.
to avoid circular references (Avoiding cyclic references)
In C #, a circular reference is not a big problem. In fact, in only one way circular references will cause problems, that is in the struct struct. Because classes are reference types, circular references and nothing hurt. Held on the source object a reference to the target object pointer on the target object while holding a reference to the source object pointer, this will not have any problems.
But if it is the structure, we can not use the pointer, which create objects on the stack. Because in this case, if the source object contains a target object, actually contains a copy of the target object, rather than the real target, and vice versa.
most cases, the compiler will detect this circular reference, and then throws a compilation error, this function is actually great. Let's look at an example of an error can cause:
1 struct FirstStruct
2 {
3 public SecondStruct Target;
4 }
5
6 struct SecondStruct
7 {
8 public FirstStruct Source;
9 }
this above code, the use of a structure variable. This class has a huge difference: even though we did not initialize the variable, but the variable has already been initialized to default values.
So, programming is a complex matter, the compiler is not omnipotent God. Through a number of ways you can fool the compiler. If we are deceived compiler, the compiler will tell us a run-time error, unable to create the object. A deception is to use automatic properties:
1 struct FirstStruct
2 {
3 public SecondStruct Target { get; set; }
4 }
5
6 struct SecondStruct
7 {
8 public FirstStruct Source { get; set; }
9 }
this does not prevent the problem from occurring, it is just the problem from a compile-time error delayed until run-time errors. Our minds will immediately generate a solution is to use Nullable structure (nullable struct).
1 struct FirstStruct
2 {
3 public SecondStruct? Target { get; set; }
4 }
5
6 struct SecondStruct
7 {
8 public FirstStruct Source { get; set; }
9 }
The problem here is that those structures can also be an empty structure, they inherited from System.Nullable
finally, Lambda expressions to save us.
1 struct FirstStruct
2 {
3 readonly Func<SecondStruct> f;
4
5 public FirstStruct(SecondStruct target)
6 {
7 f = () => target;
8 }
9
10 public SecondStruct Target
11 {
12 get
13 {
14 return f();
15 }
16 }
17 }
18
19 struct SecondStruct
20 {
21 public FirstStruct Source { get; set; }
22 }
what do we do here? We used a reference to a function, and the function will return to our structure. The compiler generates a class to contain this structure, so that this structure will exist as a global variable. Because the structure will always contain a default constructor, will remain f unreferenced state, we added another constructor, and the target structure as a parameter.
Finally, we created a closure, in which to return the captured structure instance. Focus emphasizes, there may be other possibilities. If you use a reference type as a value type of container, possibly circular references situation worse. Lambda expressions can be just one way to accomplish this function, but under certain conditions, which is able to handle this scenario of the most expressive and most direct way.
complete code
1 class TestPatterns
2 {
3 public static void SelfDefining()
4 {
5 Console.WriteLine(":: Pattern: Self-definining function");
6
7 Action foo = () =>
8 {
9 Console.WriteLine("Hi there!");
10
11 foo = () =>
12 {
13 Console.WriteLine("Hi again!");
14 };
15 };
16
17 Console.WriteLine("First call (initilization).");
18 foo();
19 Console.WriteLine("Second call - use different one now!");
20 foo();
21 Console.WriteLine("Third call - still the same.");
22 foo();
23 }
24
25 public static void Callback()
26 {
27 Console.WriteLine(":: Pattern: Callback pattern");
28 Console.WriteLine("Calling the function with lambda expression.");
29
30 CallMe(() => "The boss.");
31
32 Console.WriteLine("Back at the starting point.");
33 }
34
35 static void CallMe(Func<string> caller)
36 {
37 Console.WriteLine("Received function as parameter - Who called?!");
38 Console.WriteLine(caller());
39 }
40
41 public static void Returning()
42 {
43 Console.WriteLine(":: Pattern: Returning function");
44 Console.WriteLine("Calling to obtain the method ...");
45 Func<double, double> method = GetProperMethod("sin");
46 Console.WriteLine("Doing something with the method ...");
47 Console.WriteLine("f(pi / 4) = {0}", method(Math.PI / 4));
48 }
49
50 static Func<double, double> GetProperMethod(string what)
51 {
52 switch (what)
53 {
54 case "sin":
55 return Math.Sin;
56
57 case "cos":
58 return Math.Cos;
59
60 case "exp":
61 return Math.Exp;
62
63 default:
64 return x => x;
65 }
66 }
67
68 public static void IIFE()
69 {
70 Console.WriteLine(":: Pattern: IIFE");
71
72 ((Action<double>)((x) =>
73 {
74 Console.WriteLine(2.0 * x * x - 0.5 * x);
75 }))(1.0);
76
77
78 ((Action<double, double>)((x, y) =>
79 {
80 Console.WriteLine(2.0 * x * y - 1.5 * x);
81 }))(2.0, 3.0);
82 }
83
84 public static void ImmediateObject()
85 {
86 Console.WriteLine(":: Pattern: Immediate object initialization");
87
88 var terminator = new
89 {
90 Typ = "T1000",
91 Health = 100,
92 Hit = (Func<double, double>)((x) =>
93 {
94 return 100.0 * Math.Exp(-x);
95 })
96 };
97
98 Console.WriteLine("Terminator with type {0} has been created.", terminator.Typ);
99 Console.WriteLine("Let's hit the terminator with 0.5. Rest health would be {0}!", terminator.Hit(0.5));
100 }
101
102 public static void InitTimeBranching()
103 {
104 Console.WriteLine(":: Pattern: Init-time branching");
105 Action<int> loopBody = null;
106 Console.WriteLine("Select a proper loop body method ...");
107 Random r = new Random();
108 int sum = 0;
109
110 if (r.NextDouble() < 0.5)
111 {
112 Console.WriteLine("Selected random choice ...");
113
114 loopBody = index =>
115 {
116 sum += r.Next(0, 10000);
117 };
118 }
119 else
120 {
121 Console.WriteLine("Selected little gauss ...");
122
123 loopBody = index =>
124 {
125 sum += index;
126 };
127 }
128
129 Console.WriteLine("Execute the loop ...");
130
131 for (var i = 0; i < 10000; i++)
132 loopBody(i);
133
134 Console.WriteLine("Loop has finished with result sum = {0}.", sum);
135 }
136 }
article translated and adapted from Way to Lambda , chapters and code has a lot of changes, does not contain the entire contents.
没有评论:
发表评论