C# vNext language design – private protected – FamilyAndAssembly
A better syntax for "private protected" ?
C# vNext will have a new accessibility modifier. The C# team had first proposed to use "private protected", but maybe someone can find a better syntax for it.
On this survey every syntax that's been proposed so far has been gathered together for everyone to vote on her/his favorite.
WHAT IS THE NEW ACCESSIBILITY MODIFIER ABOUT? ... This post on StackOverflow has a great explanation.
WHERE CAN YOU JOIN THE DISCUSSION? ... Read the motives behind all these proposals - and help shape the future of your favorite programming language - on the CodePlex discussion forum
Go ahead and choose your favorite. The C# team will gathering up answers in mid May.
C# vNext language design - private protected - FamilyAndAssembly
What’s New In C# 5.0 Session Materials From Rumos InsideOut Event
Here are the materials from my What’s New In C# 5.0 session at the Rumos InsideOut Event.
Slide deck:
Sample code:
C# 5.0 Async/Await Demo Code
I’ve published the sample code I use to demonstrate the use of async/await in C# 5.0. You can find it here.
Projects
PauloMorgado.AyncDemo.WebServer
This project is a simple web server implemented as a console application using Microsoft ASP.NET Web API self hosting and serves an image (with a delay) that is accessed by the other projects.
This project has a dependency on Json.NET due to the fact the the Microsoft ASP.NET Web API hosting has a dependency on Json.NET.
The application must be run on a command prompt with administrative privileges or a urlacl must be added to allow the use of the following command:
netsh http add urlacl url=http://+:9090/ user=machine\username
To remove the urlacl, just use the following command:
netsh http delete urlacl url=http://+:9090/
PauloMorgado.AsyncDemo.WindowsForms
This Windows Forms project contains three regions that must be uncommented one at a time:
Sync with WebClient
This code retrieves the image through a synchronous call using the WebClient class.
Async with WebClient
This code retrieves the image through an asynchronous call using the WebClient class.
Async deadlock
This code how async operations can still deadlock.
Async with HttpClient with cancelation
This code retrieves the image through an asynchronous call with cancelation using the HttpClient class.
PauloMorgado.AsyncDemo.Wpf
This WPF project contains three regions that must be uncommented one at a time:
Sync with WebClient
This code retrieves the image through a synchronous call using the WebClient class.
Async with WebClient
This code retrieves the image through an asynchronous call using the WebClient class.
Async deadlock
This code how async operations can still deadlock.
Async with HttpClient with cancelation
This code retrieves the image through an asynchronous call with cancelation using the HttpClient class.
Breaking Changes In Argument List Evaluation In C# 5.0
The C# Language Specification states on §7.5.1.2 that “(…) the expressions or variable references of an argument list are evaluated in order, from left to right (…)”.
So, when this code is compiled with the C# 4.0 compiler:
static void M( int x = 10, int y = 20, int z = 30) { Console.WriteLine( "x={0}, y={1}, z={2}", x, y, z); } static void Main(string[] args) { int a = 0; M(++a, z: ++a); }
and run, this unexpected output is obtained:
x=2, y=20, z=1
In fact, fixing this compiler flaw was the cause of one of the few breaking changes introduced in C# 5.0.
Using the 5.0 compiler, the expected result is obtained:
x=1, y=20, z=2
To avoid this type of surprises, expression evaluation should be avoided in argument lists.
With this code:
int a = 0; int i = ++a; int j = ++a; M(i, z: j);
the same result is obtained for both C# 4.0 and C# 5.0:
x=1, y=20, z=2
Announcing The Microsoft Roslyn CTP
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.
-
Read the Roslyn Project Overview for a good overview of the project.
-
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.
Extension Methods And Type Inference In Action
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.
Creating Property Set Expression Trees In A Developer Friendly Way
In a previous post I showed how to create expression trees to set properties on an object.
The way I did it was not very developer friendly. It involved explicitly creating the necessary expressions because the compiler won’t generate expression trees with property or field set expressions.
Recently someone contacted me the help develop some kind of command pattern framework that used developer friendly lambdas to generate property set expression trees.
Simply putting, given this entity class:
public class Person { public string Name { get; set; } }
The person in question wanted to write code like this:
var et = Set((Person p) => p.Name = "me");
Where et is the expression tree that represents the property assignment.
So, if we can’t do this, let’s try the next best thing that is splitting retrieving the property information from the retrieving the value to assign o the property:
var et = Set((Person p) => p.Name, () => "me");
And this is something that the compiler can handle.
The implementation of Set receives an expression to retrieve the property information from and another expression the retrieve the value to assign to the property:
public static Expression<Action<TEntity>> Set<TEntity, TValue>( Expression<Func<TEntity, TValue>> propertyGetExpression, Expression<Func<TValue>> valueExpression)
The implementation of this method gets the property information form the body of the property get expression (propertyGetExpression) and the value expression (valueExpression) to build an assign expression and builds a lambda expression using the same parameter of the property get expression as its parameter:
public static Expression<Action<TEntity>> Set<TEntity, TValue>( Expression<Func<TEntity, TValue>> propertyGetExpression, Expression<Func<TValue>> valueExpression) { var entityParameterExpression = (ParameterExpression)(((MemberExpression)(propertyGetExpression.Body)).Expression); return Expression.Lambda<Action<TEntity>>( Expression.Assign(propertyGetExpression.Body, valueExpression.Body), entityParameterExpression); }
And now we can use the expression to translate to another context or just compile and use it:
var et = Set((Person p) => p.Name, () => name); Console.WriteLine(person.Name); // Prints: p => (p.Name = “me”) var d = et.Compile(); d(person); Console.WriteLine(person.Name); // Prints: me
It can even support closures:
var et = Set((Person p) => p.Name, () => name); Console.WriteLine(person.Name); // Prints: p => (p.Name = value(<>c__DisplayClass0).name) var d = et.Compile(); name = "me"; d(person); Console.WriteLine(person.Name); // Prints: me name = "you"; d(person); Console.WriteLine(person.Name); // Prints: you
Not so useful in the intended scenario (but still possible) is building an expression tree that receives the value to assign to the property as a parameter:
public static Expression<Action<TEntity, TValue>> Set<TEntity, TValue>(Expression<Func<TEntity, TValue>> propertyGetExpression) { var entityParameterExpression = (ParameterExpression)(((MemberExpression)(propertyGetExpression.Body)).Expression); var valueParameterExpression = Expression.Parameter(typeof(TValue)); return Expression.Lambda<Action<TEntity, TValue>>( Expression.Assign(propertyGetExpression.Body, valueParameterExpression), entityParameterExpression, valueParameterExpression); }
This new expression can be used like this:
var et = Set((Person p) => p.Name); Console.WriteLine(person.Name); // Prints: (p, Param_0) => (p.Name = Param_0) var d = et.Compile(); d(person, "me"); Console.WriteLine(person.Name); // Prints: me d(person, "you"); Console.WriteLine(person.Name); // Prints: you
The only caveat is that we need to be able to write code to read the property in order to write to it.
LINQ: Implementing The SkipLastWhile Operator
Following my last posts (>)(>), in this post I’ll introduce the implementation of the SkipLastWhile operator.
The SkipLastWhile returns all but the last contiguous elements from a a sequence that satisfy the specified criteria and is implemented as the SkipLastWhile extension methods:
public static IEnumerable<TSource> SkipLastWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
public static IEnumerable<TSource> SkipLastWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
The implementation of these methods is very simple. We start with an empty buffer and buffer every item that satisfies the criteria implemented by a predicate. Whenever an item doesn’t satisfy the criteria, all buffered items are yield, the buffer is cleared and the the item that doesn’t satisfy the criteria is yield:
var buffer = new List<TSource>(); foreach (var item in source) { if (predicate(item)) { buffer.Add(item); } else { if (buffer.Count > 0) { foreach (var bufferedItem in buffer) { yield return bufferedItem; } buffer.Clear(); } yield return item; } }
The overload that takes in account the index of the item only differs in the call the predicate that implements the criteria:
var buffer = new List<TSource>(); var idx = 0; foreach (var item in source) { if (predicate(item, idx++)) { buffer.Add(item); } else { if (buffer.Count > 0) { foreach (var bufferedItem in buffer) { yield return bufferedItem; } buffer.Clear(); } yield return item; } }
You can find the complete implementation of this operator (and more) CodePlex project for LINQ utilities and operators: PauloMorgado.Linq
LINQ: Implementing The SkipLast Operator
Following my last post, in this post I’ll introduce the implementation of the SkipLast operator.
The SkipLast operator returns all but a specified number of contiguous elements from the end of a sequence and is implemented as the SkipLast extension method:
public static IEnumerable<TSource> SkipLast<TSource>(this IEnumerable<TSource> source, int count)
To implement this operator, first we start by buffering, at most, a count number of items from the source sequence in an array that acts as a circular buffer:
var sourceEnumerator = source.GetEnumerator(); var buffer = new TSource[count]; int idx; for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++) { buffer[idx] = sourceEnumerator.Current; }
Next, we iterate over the rest of the items of the source sequence circularly buffering them and yielding the previously buffered item at the same postition:
idx = 0; while (sourceEnumerator.MoveNext()) { var item = buffer[idx]; buffer[idx] = sourceEnumerator.Current; idx = (idx + 1) % count; yield return item; }
If the number of items to skip is greater or equal to the number of items in the source sequence, sourceEnumerator.MoveNext() will return false on the first iteration of the while loop and an empty sequence will be produced.
As with the TakeLast operator, a few optimizations can be made here.
The first is obvious, if the requested number of items is 0 (zero) or lower, we just return an equivalent sequence:
if (count <= 0) { return source.Select(i => i); }
The second is if the source sequence is known to implement the IList<T> interface. Objects implementing this interface have a Count property and indexed access to its items which allows us to optimize the production of the final sequence.
If the number of items to skip is equal to or greater than the number of items in the source sequence, we just return an empty sequence:
var list = source as IList<TSource>; if (list != null) { if (count >= list.Count) { return System.Linq.Enumerable.Empty<TSource>(); } // ... }
If the number of items in the source sequence is greater than the number of items to skip, producing the final sequence consists of yielding all the items in the source sequence except the last count items:
int returnCount = list.Count - count; for (int idx = 0; idx < returnCount; idx++) { yield return list[idx]; }
You can find the complete implementation of this operator (and more) CodePlex project for LINQ utilities and operators: PauloMorgado.Linq
LINQ: Introducing The Skip Last Operators
After having introduced the TakeLast operators (>)(>)(>), it makes sense to introduce their duals: the SkipLast operators.
Name | Description | Example |
---|---|---|
SkipLast<TSource>(IEnumerable<TSource>) |
Returns all but a specified number of contiguous elements from the end of a sequence. |
int[] grades = { 59, 82, 70, 56, 92, 98, 85 }; var lowerGrades = grades .OrderBy(g => g) .SkipLast(3); Console.WriteLine("All grades except the top three are:"); foreach (int grade in lowerGrades) { Console.WriteLine(grade); } /* This code produces the following output: All grades except the top three are: 56 59 70 82 */ |
SkipLastWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) |
Returns all the elements from sequence skipping those at the end as long as the specified condition is true. |
int[] grades = { 59, 82, 70, 56, 92, 98, 85 }; var lowerGrades = grades .OrderBy(grade => grade) .SkipLastWhile(grade => grade >= 80); Console.WriteLine("All grades below 80:"); foreach (int grade in lowerGrades) { Console.WriteLine(grade); } /* This code produces the following output: All grades below 80: 56 59 70 */ |
SkipLastWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) |
Returns all the elements from sequence skipping those at the end as long as the specified condition is true. |
int[] amounts = { 5000, 2500, 5500, 8000, 6500, 4000, 1500, 9000 }; var query = amounts .SkipLastWhile((amount, index) => amount > index * 1000); foreach (int amount in query) { Console.WriteLine(amount); } /* This code produces the following output: 9000 */ |
You can find these (and more) operators in my CodePlex project for LINQ utilities and operators: PauloMorgado.Linq
Recent Comments