The Roslyn team has announced general availability of the Roslyn CTP!
The official launch is at http://msdn.com/roslyn, and there were a number of blogs to publicize the availability broadly (soma, ericli, vsteam, vbteam, c#faq) and across twitter.
This release marks a significant step to the new way of thinking of compilers, and the agility that is now possible with language innovation, IDE tooling, and powering the ecosystem. The C# and VB compilers are no longer black boxes – something we put source text into, do some magic on, and get an assembly out. All that rich information about code is no longer thrown away, but is now exposed as a full-fidelity object model that can be easily consumed by all. In addition, it was released a preview of the first-ever Interactive window for C# that contains full IDE support – including IntelliSense and even automatically detecting missing using directives.
How to get started:
-
Download the
CTP. The CTP installs on Visual Studio 2010 SP1 and can be safely installed side-by-side with Visual Studio 11.
-
Go to Start -> All Programs -> Microsoft Codename Roslyn CTP -> Getting Started to launch the entry point into all the documentation, samples, and tools.
-
-
Learn from the rich samples included (paste as C#/VB, refactorings, code analysis, and code generation tools).
-
Run the
walkthroughs to learn about the Compiler APIs, the Services API, or using the Interactive window.
-
For those of you that aren’t extension writers, download the CTP to try out the Interactive window and use the Copy Paste C#/VB extensions that were built to help with your daily work now!
The release includes the following features:
-
Visual Studio Project Templates
These project templates help you get started using the Roslyn APIs and building new Visual Studio extensions using the C# or VB APIs.
-
Reference Assemblies
The Roslyn assemblies can be added to projects via the Add Reference dialog.
-
Interactive Window
A new tool window called C# Interactive is available in Visual Studio by invoking View -> Other Windows -> C# Interactive from the menu. You can explore by either executing snippets of code in the C# Interactive tool window, or cumulatively building up execution context as you experiment.
-
Script File Editing Support
C# Script (.csx) files allow top-level statements much like the C# Interactive window. You can create a new C# Script file by invoking File -> New File -> Script -> Visual C# Script from the Visual Studio menu. In addition to typing directly into the tool window, you can also select code in C# and C# Script (.csx) files and invoke "Execute in Interactive" or "Copy to Interactive" from the context menu. C# Script editing features like IntelliSense are powered by the Roslyn Language Service.
Please keep in mind that this is only a technology preview, and it’s not done yet! The primary goal of this CTP is to gather feedback on the public APIs and give an early look at the Interactive window feature. The shape of the APIs are in a fairly stable state, especially the Compiler ones, but there are still a set of known limitations and only a subset of the C# and Visual Basic languages are implemented in the current release. For a full list of non-implemented language features, see here. The Interactive window is only available for C# at this time, but VB is following shortly.
The Roslyn team looks forward to hearing your feedback on the forums e through Connect.
While participating in a forum discussion, the need to clean up HTML from "dangerous" constructs came up.
In the present case it was needed to remove SCRIPT, OBJECT, APPLET, EMBBED, FRAMESET, IFRAME, FORM, INPUT, BUTTON and TEXTAREA elements (as far as I can think of) from the HTML source. Every event attribute (ONEVENT) should also be removed keep all other attributes, though.
HTML is very loose and extremely hard to parse. Elements can be defined as a start tag (<element-name>) and an end tag (</element-name>) although some elements don't require the end tag. If XHTML is being parsed, elements without an end tag require the tag to be terminated with /> instead of just >.
Attributes are not easier to parse. By definition, attribute values are required to be delimited by quotes (') or double quotes ("), but some browsers accept attribute values without any delimiter.
We could build a parser, but then it will become costly to add or remove elements or attributes. Using a regular expression to remove unwanted elements and attributes seems like the best option.
First, lets capture all unwanted elements with start and end tags. To capture these elements we must:
-
Capture the begin tag character followed by the element name (for which we will store its name - t): <(?<t>element-name)
-
Capture optional white spaces followed by any character: (\s+.*?)?
-
Capture the end tag character: >
-
Capture optional any characters: .*?
-
Capture the begin tag character followed by closing tag character, the element name (referenced by the name - t) and the end tag character: </\k<t>>
<(?<t>tag-name(\s+.*?)?>.*?</\k<t>>
To capture all unwanted element types, we end up with the following regular expression:
<(?<t>script|object|applet|embbed|frameset|iframe|form|textarea)(\s+.*?)?>.*?</\k<t>>
Next, lets capture all unwanted elements without an end tag. To capture these elements we must:
-
Capture the begin tag character followed by the element name: <element-name
-
Capture optional white spaces followed by any character: (\s+.*?)?
-
Capture an optional closing tag character: /?
-
Capture the end tag character: >
<tag-name(\s+.*?)?/?>
To capture all unwanted element types, we end up with the following regular expression:
<(script|object|applet|embbed|frameset|iframe|form|textarea|input|button)(\s+.*?)?/?>
To remove those unwanted elements from the source HTML, we can combine these two previous regular expressions into one and replace any match with an empty string:
Regex.Replace(
sourceHtml,
"|(<(?<t>script|object|applet|embbed|frameset|iframe|form|textarea)(\\s+.*?)?>.*?</\\k<t>>)"
+ "|(<(script|object|applet|embbed|frameset|iframe|form|input|button|textarea)(\\s+.*?)?/?>)" ,
string.Empty);
And finally, the unwanted attributes. This one is trickier because we want to capture unwanted attributes inside an element's start tag. To achieve that, we need to match an element's opening tag and capture all attribute definitions. To capture these attributes we must:
(?<=<\w+)((?:\s+)(\w+=(("[^"]*")|('[^']*')|(.*?)))*(?=/?>)
The problem with the previous regular expression is that it matches the start tag and captures the whole list of attributes and not each unwanted attribute by itself. This prevents us from from replacing each match with a fixed value (empty string).
To solve this, we have to name what we want to capture and use the Replace overload that uses a MatchEvaluator.
We could capture unwanted attributes as we did for the unwanted elements, but then we would need to remove them from the list of all the element’s attributes. Instead, we’ll capture the wanted attributes and build the list of attributes. To identify the wanted attributes, we’ll need to name them (a). The resulting code will be something like this:
Regex.Replace(
sourceHtml,
"((?<=<\\w+)((?:\\s+)((?:on\\w+=((\"[^\"]*\")|('[^']*')|(.*?)))|(?<a>(?!on)\\w+=((\"[^\"]*\")|('[^']*')|(.*?)))))*(?=/?>))",
match =>
{
if (!match.Groups["a"].Success)
{
return string.Empty;
}
var attributesBuilder = new StringBuilder();
foreach(Capture capture in match.Groups["a"].Captures)
{
attributesBuilder.Append(' ');
attributesBuilder.Append(capture.Value);
}
return attributesBuilder.ToString();
}
);
To avoid parsing the source HTML more than once, we can combine all the regular expressions into a single one.
Because we are still outputting only the wanted attributes, there’s no change to the match evaluator.
A few options (RegexOptions) will also be added to increase functionality and performance:
- IgnoreCase: For case-insensitive matching.
- CultureInvariant: For ignoring cultural differences in language.
- Multiline: For multiline mode.
- ExplicitCapture: For capturing only named captures.
- Compiled: For compiling the regular expression into an assembly. Only if the regular expression is to be used many times.
The resulting code will be this:
Regex.Replace(
sourceHtml,
"(<(?<t>script|object|applet|embbed|frameset|iframe|form|textarea)(\\s+.*?)?>.*?</\\k<t>>)"
+ "|(<(script|object|applet|embbed|frameset|iframe|form|input|button|textarea)(\\s+.*?)?/?>)"
+ "|((?<=<\\w+)((?:\\s+)((?:on\\w+=((\"[^\"]*\")|('[^']*')|(.*?)))|(?<a>(?!on)\\w+=((\"[^\"]*\")|('[^']*')|(.*?)))))*(?=/?>))",
match =>
{
if (!match.Groups["a"].Success)
{
return string.Empty;
}
var attributesBuilder = new StringBuilder();
foreach(Capture capture in match.Groups["a"].Captures)
{
attributesBuilder.Append(' ');
attributesBuilder.Append(capture.Value);
}
return attributesBuilder.ToString();
},
RegexOptions.IgnoreCase
| RegexOptions.Multiline
| RegexOptions.ExplicitCapture
| RegexOptions.CultureInvariant
| RegexOptions.Compiled
);
This was not extensively tested and there might be some wanted HTML remove and some unwanted HTML kept, but it’s probably very close to a good solution.
I make extensive use of extension methods, either to make classes small and focused or to improve readability.
While porting a .NET 1.1 WinForms application to C# 3.0, I found lots of code like this:
delegate int Int32DelegateStringBoolean(string text, bool flag);
void DoStuff()
{
// ...
var x = (int)this.Invoke(new Int32DelegateStringBoolean(GetStuff), new object[] { "some text", true });
// ...
}
int GetStuff(string text, bool flag)
{
// ...
}
.NET 2.0 introduced a nicer API and it became possible to write the code calling Invoke like this:
var x = (int)this.Invoke(new Int32DelegateStringBoolean(GetStuff), "some text", true);
But it’s still not strongly typed enough to my taste and the compiler can’t verify if any mistake was made. This will still be valid code at compile time that will break at run time:
var x = (long)this.Invoke(new Int32DelegateStringBoolean(GetStuff), "some text", 10M, 5);
To make the code safer and more readable, I decided to create extension methods to extend the Control class and provide strongly type Invoke methods.
Instead of defining custom delegates for each need, I used the Action and Func delegates exiting in the framework and wrote extension methods like this:
public static TResult InvokeFunc<T1, T2, TResult>(this Control control, Func<T1, T2, TResult> func, T1 param1, T2 param2)
{
return (TResult)(control.Invoke(func, param1, param2));
}
Now I can replace the call to Invoke with this call:
var x = this.InvokeFunc<string, bool, int>(new Func<string, bool, int>(GetStuff), "some text", true);
And the compiler is now able to match the type of the delegate, the parameters and the return value.
Starting with the C# 2.0 compiler, there is no need to write the delegate instantiation if the compiler can infer the type of the delegate, which makes the code even simpler:
var x = this.InvokeFunc<string, bool, int>(GetStuff, "some text", true);
The C# compiler is even capable of inferring the type parameters of the InvokeFunc method making the code even smaller and more readable:
var x = this.InvokeFunc(GetStuff, "some text", true);
A lot better than what we started with, isn’t it?
So far, I’ve implemented these:
/// <summary>
/// Provides extended functionality to <see cref="System.Windows.Forms.Control"/>.
/// </summary>
public static class ControlExtensions
{
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to invoke the function on.</param>
/// <param name="func">The function to invoke.</param>
/// <returns>A <typeparamref name="TResult"/> that contains the return value from the function (<paramref name="func"/>) being invoked.</returns>
public static TResult InvokeFunc<TResult>(this Control control, Func<TResult> func)
{
return (TResult)(control.Invoke(func));
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to invoke the function on.</param>
/// <param name="func">The function to invoke.</param>
/// <param name="param1">The parameter of the action.</param>
/// <returns>A <typeparamref name="TResult"/> that contains the return value from the function (<paramref name="func"/>) being invoked.</returns>
public static TResult InvokeFunc<T1, TResult>(this Control control, Func<T1, TResult> func, T1 param1)
{
return (TResult)(control.Invoke(func, param1));
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the function.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to invoke the function on.</param>
/// <param name="func">The function to invoke.</param>
/// <param name="param1">The first parameter of the function.</param>
/// <param name="param2">The second parameter of the function.</param>
/// <returns>A <typeparamref name="TResult"/> that contains the return value from the function (<paramref name="func"/>) being invoked.</returns>
public static TResult InvokeFunc<T1, T2, TResult>(this Control control, Func<T1, T2, TResult> func, T1 param1, T2 param2)
{
return (TResult)(control.Invoke(func, param1, param2));
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the function.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the function.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to invoke the function on.</param>
/// <param name="func">The function to invoke.</param>
/// <param name="param1">The first parameter of the function.</param>
/// <param name="param2">The second parameter of the function.</param>
/// <param name="param3">The third parameter of the function.</param>
/// <returns>A <typeparamref name="TResult"/> that contains the return value from the function (<paramref name="func"/>) being invoked.</returns>
public static TResult InvokeFunc<T1, T2, T3, TResult>(this Control control, Func<T1, T2, T3, TResult> func, T1 param1, T2 param2, T3 param3)
{
return (TResult)(control.Invoke(func, param1, param2, param3));
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the function.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the function.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the function.</typeparam>
/// <typeparam name="T4">The type of the forth parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to invoke the function on.</param>
/// <param name="func">The function to invoke.</param>
/// <param name="param1">The first parameter of the function.</param>
/// <param name="param2">The second parameter of the function.</param>
/// <param name="param3">The third parameter of the function.</param>
/// <param name="param4">The forth parameter of the function.</param>
/// <returns>A <typeparamref name="TResult"/> that contains the return value from the function (<paramref name="func"/>) being invoked.</returns>
public static TResult InvokeFunc<T1, T2, T3, T4, TResult>(this Control control, Func<T1, T2, T3, T4, TResult> func, T1 param1, T2 param2, T3 param3, T4 param4)
{
return (TResult)(control.Invoke(func, param1, param2, param3, param4));
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <param name="control">The control to invoke the action on.</param>
/// <param name="action">The action to invoke.</param>
public static void InvokeAction(this Control control, Action action)
{
control.Invoke(action);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T">The type of the parameter.</typeparam>
/// <param name="control">The control to invoke the action on.</param>
/// <param name="action">The action to invoke.</param>
/// <param name="param">The parameter of the action.</param>
public static void InvokeAction<T>(this Control control, Action<T> action, T param)
{
control.Invoke(action, param);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the action.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the action.</typeparam>
/// <param name="control">The control to invoke the action on.</param>
/// <param name="action">The action to invoke.</param>
/// <param name="param1">The first parameter of the action.</param>
/// <param name="param2">The second parameter of the action.</param>
public static void InvokeAction<T1, T2>(this Control control, Action<T1, T2> action, T1 param1, T2 param2)
{
control.Invoke(action, param1, param2);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the action.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the action.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the action.</typeparam>
/// <param name="control">The control to invoke the action on.</param>
/// <param name="action">The action to invoke.</param>
/// <param name="param1">The first parameter of the action.</param>
/// <param name="param2">The second parameter of the action.</param>
/// <param name="param3">The third parameter of the action.</param>
public static void InvokeAction<T1, T2, T3>(this Control control, Action<T1, T2, T3> action, T1 param1, T2 param2, T3 param3)
{
control.Invoke(action, param1, param2, param3);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the action.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the action.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the action.</typeparam>
/// <typeparam name="T4">The type of the forth parameter of the action.</typeparam>
/// <param name="control">The control to invoke the action on.</param>
/// <param name="action">The action to invoke.</param>
/// <param name="param1">The first parameter of the action.</param>
/// <param name="param2">The second parameter of the action.</param>
/// <param name="param3">The third parameter of the action.</param>
/// <param name="param4">The forth parameter of the action.</param>
public static void InvokeAction<T1, T2, T3, T4>(this Control control, Action<T1, T2, T3, T4> action, T1 param1, T2 param2, T3 param3, T4 param4)
{
control.Invoke(action, param1, param2, param3, param4);
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to BeginInvoke the function on.</param>
/// <param name="func">The function to BeginInvoke.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeFunc<TResult>(this Control control, Func<TResult> func)
{
return control.BeginInvoke(func);
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to BeginInvoke the function on.</param>
/// <param name="func">The function to BeginInvoke.</param>
/// <param name="param1">The parameter of the action.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeFunc<T1, TResult>(this Control control, Func<T1, TResult> func, T1 param1)
{
return control.BeginInvoke(func, param1);
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the function.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to BeginInvoke the function on.</param>
/// <param name="func">The function to BeginInvoke.</param>
/// <param name="param1">The first parameter of the function.</param>
/// <param name="param2">The second parameter of the function.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeFunc<T1, T2, TResult>(this Control control, Func<T1, T2, TResult> func, T1 param1, T2 param2)
{
return control.BeginInvoke(func, param1, param2);
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the function.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the function.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to BeginInvoke the function on.</param>
/// <param name="func">The function to BeginInvoke.</param>
/// <param name="param1">The first parameter of the function.</param>
/// <param name="param2">The second parameter of the function.</param>
/// <param name="param3">The third parameter of the function.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeFunc<T1, T2, T3, TResult>(this Control control, Func<T1, T2, T3, TResult> func, T1 param1, T2 param2, T3 param3)
{
return control.BeginInvoke(func, param1, param2, param3);
}
/// <summary>
/// Executes the specified function (<paramref name="func"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the function.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the function.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the function.</typeparam>
/// <typeparam name="T4">The type of the forth parameter of the function.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="control">The control to BeginInvoke the function on.</param>
/// <param name="func">The function to BeginInvoke.</param>
/// <param name="param1">The first parameter of the function.</param>
/// <param name="param2">The second parameter of the function.</param>
/// <param name="param3">The third parameter of the function.</param>
/// <param name="param4">The forth parameter of the function.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeFunc<T1, T2, T3, T4, TResult>(this Control control, Func<T1, T2, T3, T4, TResult> func, T1 param1, T2 param2, T3 param3, T4 param4)
{
return control.BeginInvoke(func, param1, param2, param3, param4);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <param name="control">The control to BeginInvoke the action on.</param>
/// <param name="action">The action to BeginInvoke.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeAction(this Control control, Action action)
{
return control.BeginInvoke(action);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T">The type of the parameter.</typeparam>
/// <param name="control">The control to BeginInvoke the action on.</param>
/// <param name="action">The action to BeginInvoke.</param>
/// <param name="param">The parameter of the action.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeAction<T>(this Control control, Action<T> action, T param)
{
return control.BeginInvoke(action, param);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the action.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the action.</typeparam>
/// <param name="control">The control to BeginInvoke the action on.</param>
/// <param name="action">The action to BeginInvoke.</param>
/// <param name="param1">The first parameter of the action.</param>
/// <param name="param2">The second parameter of the action.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeAction<T1, T2>(this Control control, Action<T1, T2> action, T1 param1, T2 param2)
{
return control.BeginInvoke(action, param1, param2);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the action.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the action.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the action.</typeparam>
/// <param name="control">The control to BeginInvoke the action on.</param>
/// <param name="action">The action to BeginInvoke.</param>
/// <param name="param1">The first parameter of the action.</param>
/// <param name="param2">The second parameter of the action.</param>
/// <param name="param3">The third parameter of the action.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeAction<T1, T2, T3>(this Control control, Action<T1, T2, T3> action, T1 param1, T2 param2, T3 param3)
{
return control.BeginInvoke(action, param1, param2, param3);
}
/// <summary>
/// Executes the specified action (<paramref name="action"/>) on the thread that owns the control's underlying window handle.
/// </summary>
/// <typeparam name="T1">The type of the first parameter of the action.</typeparam>
/// <typeparam name="T2">The type of the second parameter of the action.</typeparam>
/// <typeparam name="T3">The type of the third parameter of the action.</typeparam>
/// <typeparam name="T4">The type of the forth parameter of the action.</typeparam>
/// <param name="control">The control to BeginInvoke the action on.</param>
/// <param name="action">The action to BeginInvoke.</param>
/// <param name="param1">The first parameter of the action.</param>
/// <param name="param2">The second parameter of the action.</param>
/// <param name="param3">The third parameter of the action.</param>
/// <param name="param4">The forth parameter of the action.</param>
/// <returns>An System.IAsyncResult that represents the result of the operation.</returns>
public static IAsyncResult BeginInvokeAction<T1, T2, T3, T4>(this Control control, Action<T1, T2, T3, T4> action, T1 param1, T2 param2, T3 param3, T4 param4)
{
return control.BeginInvoke(action, param1, param2, param3, param4);
}
}
Use them if you need to.