Lambda expression is clearer than the combination of definition and Out-of-band method definitions, and the additional work involved is only required to satisfy the language definition. However, it also has some deficiencies. If the parameter of a method contains an abstract type such as System.Delegate, a lambda expression is used to introduce the special problem: The C # compiler cannot convert a lambda expression to a derived representative type that is not yet explicitly defined.
If you don't think about it, your code will look like it's coming from. NET1.0 of things. In this article, I'll tell you why a lambda expression is not enough to be directly converted to an abstract representative type, and teach you how to make the compiler convert the specified delegate you define. The solution relies on Windows presentation Foundation (WPF) and System.Windows.Threading.Dispatcher components, but the issue is not strictly a WPF issue in the strictest sense. The problems described in the article appear in several. NET Framework, including the Windows Forms,office application interface and the mapping application interface. You can deal with similar problems according to the following methods.
No matter when I use. NET Framework, I would prefer to use a lambda expression instead of a more detailed expression, with an application interface from a parameter representing a table. For example, this line of code creates a System.Windows.Threading.Timer that, when the timer fails, calls a Tickhandler method:
tick = new System.Threading.Timer (unused) =>
Tickhandler ());
If the content of the method is small enough, I will use the content of the method instead of the Tickhandler () method call. This method works in most cases, but this technique does not work when the application interface takes System.Delegate as a parameter. For example, we pass the System.Windows.Controls.Dispatcher.Invoke () method through a thread implementation call in WPF:
public Object Invoke (
Delegate method,
params object[] args)
Now consider what happens when we try to execute such a call with a lambda expression:
MyTime.Dispatcher.Invoke (() => dosomething ());
There will be a hidden error:
Error Cs1660:cannot convert lambda expression to
Type ' System.Delegate ' because it is not a Delegate type
Perhaps the first time you see this error, you still do not know what is going on. Of course, this is indeed a representative type. Compilers are not as flexible as people. The System.Delegate type is an abstract type and the inference tool of that type cannot infer the number and kind of the derived variable or some of the return values used for the unknown representative type. To resolve this problem, we must create a specific representative type and specify a lambda expression for that type. Remember, the representative type requires that you treat the method as data.
I created a WPF timer program to show how it works, and it explains how c#3.0 simplifies the operation of an older application interface (the following figure).
When you do the demo, the application in the example runs a timer, and as the set time passes, its color turns from green to yellow and then to red. This is a good demonstration of a method called across threads because the timer runs in the background thread.
Updating the demo according to the time change requires a response to events originating from the timer. The timer runs in the background thread, so you can easily make the mistake we mentioned earlier.
Update application
The user interface handles simple code. It takes effect when the timer fails, and the code updates the display of the timer. This update must change the text, or control the background. As shown below:
Mytime.background = Newbrush;
mytime.content = Label
The timer runs on the background thread, so you need to execute the call by using the Dispatcher.invoke () boundary line. These two lines of code are the code you want to include in the lambda expression, not the logical justification for proving the method definition. But I've said before that Lambda does not work with didpatcher.invoke unless you use a specific representative definition. Part of this is already in. NET Framework 3.5.
We can use embedded representations to define and assign them, and these are the solutions that are more convenient than the cases mentioned earlier. These two lines of code also require a pair of arguments: a string for text and a color brush for the background color. This means that you need to use the representative definition to take these two parameters into account and return an invalid value:
Action Updatetimer;
After declaring a variable, you can specify the representative variables you want to execute for your code. Here you can use lambda expressions, because the action is a specific representative definition:
Updatetimer = (label, Newbrush) =>
{
Mytime.background = Newbrush;
mytime.content = label;
};
Now, when the timer presents the event, you already have some variables that need to be executed to point to that code. The next thing to do is to use the representative definition through Dispatcher.invoke ():
if (! MyTime.Dispatcher.CheckAccess ())
{
MyTime.Dispatcher.Invoke (Updatetimer,
Newlabel, next);
}
Else
Updatetimer (Newlabel, next);
The process is simple, but it requires you to do it over and over again, so we can make the steps easier.
Here in fact by a simple pattern. The event handler can be invoked from the background thread. When we use timers, or call Web services asynchronously and other similar tasks, you see this behavior. Whenever we are not sure which thread we are on, we can call Dispatcher.checkaccess () to determine whether any user interface controls can be accessed. If you need to execute a call from a thread boundary, you must use Dispatcher.invoke (). The Dispatcher.invoke () method avoids a number of overload problems caused by the use of parameter arrays of method parameters. It uses a type of abstract representation that we want to perform.
You want a single way to check if you need to organize your choreography. If necessary, the method is choreographed, otherwise the method specified by the delegate is invoked. Your hypocritical method appears as a member of the System.Windows.Controls.Control type. This allows you to use the code as part of the control. C#3.0 gives you a way to do this: Extend the method. You need to write different overloads of the methods that allow you to use them with different parameters:
public static class Wpfextensions:
{
public static voidinvokeifneeded (
This control widget,
Action Whattodo)
{
if (!widget. Dispatcher.
CheckAccess ())
Widgets. Dispatcher.invoke (Whattodo);
Else
Whattodo ();
}
public static void
Invokeifneeded (
This controlwidget, Action
Whattodo, T parm)
{
if (!widget. Dispatcher.checkaccess ())
Widgets. Dispatcher.invoke (Whattodo, parm);
Else
Whattodo (Parm);
}
public static void
Invokeifneeded (This
Controlwidget, Action
Whattodo,
T1 Parm1, T2 parm2)
{
if (!widget. Dispatcher.
CheckAccess ())
Widgets. Dispatcher.
Invoke (Whattodo,
Parm1, Parm2);
Else
Whattodo (Parm1, Parm2);
}
}
Of course, we can also add more overloads to extend this class by adding more parameters. This is actually a simple extension.
There is a way to make WPF designers crazy: They want to simplify the use of dispatcher objects by minimizing the area of the application's interface. The use of this object is extended by using the parameters in the abstract representation and parameter list.
Any method with parameters can be used. However, there is a shortcoming in doing so. The application interface is more abstract, it destroys all types of security, and doing so can damage the compiler's ability to use type inference, thereby reducing productivity. What needs to be done is to add the layer type of your own security extension method, which can be invoked in type safety and more abstract. NET Library application interface to provide a layer.