Sample code available here that exemplifies this bug (requires Visual Studio 2008 Beta 2 and SQL Server).
So here is an incredibly unintuitive problem I ran into with anonymous delegates (same will happen for lambda expressions) in C# while using them inside loops. This will also happen in a few other circumstances (for example, in LINQ) , as I will explain in a minute below.
Symptom:
When using an anonymous delegate or lambda expression inside a loop, the results of the delegates execution (outside of the loop) are unexpected. For example:
-
Your expression is not evaluated as you expect and returns an unexpected value.
-
Your LINQ or DLINQ (LINQ2SQL) execution creates SQL or a query result which is not consistant with your assumptions based on how your loop was constructed.
This problem exists when you create an anonymous delegate inside a loop, using the loop's variable within the delegate, or when you change a variable after creating an anonymous delegate. The result is sensibly by design but pretty misleading, especially the first time you see it. Take the example below. This example was sent to me by a Microsoft employee after I filed a bug with them. He claims this is by design, and conceptually I agree with him. Can you guess what would be returned with the statement below?
1: const int count = 10;
2: Predicate<int>[] predicates = new Predicate<int>[count];
3:
4: for (int i = 0; i < count; i++)
5: { 6: predicates[ i ] = delegate(int j) { return i == j; }; 7: }
8:
9: Console.WriteLine(predicates[0](0)); // False
10: Console.WriteLine(predicates[0](count-1)); // True
When the first predicate (predicates[0]) is called in above, one may expect it to return true because when it was created i == 0. This is where it gets confusing. In the closure of the anonymous delegate, the variable i is held by reference, not by value. Because int i is declared outside of the loop, i within the delegate's closure will increment along with the for loop. Once we leave the for loop, i is the max value of i throughout the loop (or count-1). Not what you were expecting? Me either.
The next example shows the "correct" way of dealing with this, such that line 9 of the code above returns true.
1: for (int k = 0; k < count; k++)
2: { 3: int l = k;
4: predicates[k] = delegate(int m) { return l == m; }; 5: }
6:
7: Console.WriteLine(predicates[0](0)); // True
In this case, because variable l is created within the for loop, holding reference to l in the delegate is okay, because the value of l will never change, and therefore we get our expected result. Personally, I was originally expecting it to hold the value of the variable, not the reference to the variable.
This brings us to another interesting example (my original, which you may download the source code to below), where I construct a DLINQ where clause in a loop. Look at the where clause constructed below.
1: // Create a few new items that we can test with.
2: TestEntity[] testData = new TestEntity[] { 3: new TestEntity(1, "One"),
4: new TestEntity(2, "Two"),
5: new TestEntity(3, "Three") };
6:
7: // Add all our test data and submit it to the server
8: foreach (TestEntity item in testData)
9: { 10: context.TestEntities.Add(item);
11: Console.WriteLine(item.Name);
12: }
13:
14: context.SubmitChanges();
15:
16: var result = from item in context.TestEntities
17: select item;
18:
19: // Go through all our local items and append "WHERE" clauses to the
20: // result statement. This is kind of like doing a "NOT IN"
21: foreach (TestEntity localItem in testData)
22: { 23: // See note in FixedTest for diagnosis.
24: result = result.Where(sqlItem => sqlItem.Name != localItem.Name);
25: }
One would expect that the WHERE clause would exclude all the items in the testData array ("one", "two" and "three" would not be selected). However, because localItem is held by reference, only the third item ("three") is not selected. The code below will print "one" and "two" on seperate lines:
1: // The WHERE clauses above should have effectively cancelled out all
2: // the items in the database and left us selecting nothing.
3: foreach (var item in result)
4: { 5: Console.WriteLine(item.Name);
6: }
One would have expected nothing to be printed to the console by simply reading the code.
You can download some sample code here for this bug (Visual Studio 2008 Beta 2). Note that you will need a SQL Server database at localhost to run this properly.
Thank you to Colin Meek of Microsoft for contributing some of the sample code above, and helping clarify that this functionality is by design in C#.
Update:
To clarify, I'm not saying that this behavior doesn't make sense, but more that its not expected. I think this should at least provide a compiler warning (I believe VB does this) to tell you that you could possibly be confusing something in your logic. Because of LINQ's delay-execute, this problem becomes more obvious in the "Where" example.
Trying to decide how to write some unit test helper classes, I ran into an interesting question. What happens when you use the new keyword along with .NET generics? The example below shows my dilemma:
1: [TestMethod]
2: public void DoBase()
3: { 4: DoT<Base>(new Base());
5: }
6:
7: [TestMethod]
8: public void DoDerived()
9: { 10: DoT<Derived>(new Derived());
11: }
12:
13: public void DoT<T>(T item)
14: where T : Base
15: { 16: item.Blah();
17: }
18:
19: public class Base
20: { 21: public Base()
22: { 23: }
24:
25: public void Blah()
26: { 27: Console.WriteLine("Hello"); 28: }
29: }
30:
31: public class Derived : Base
32: { 33: public new void Blah()
34: { 35: Console.WriteLine("Bye"); 36: }
37: }
The question is what happens when you call DoDerived()? Because the class is typed as T (which in this case is the Derived class), you would expect "Bye" to be written to the console. How would that work though, since the compiler has no concept of Derived.Blah, and therefore cannot generate the IL to access it at compile time of the generic?
Sure enough, "Hello" will be written from Base.Blah, as if we were cast to Base at the time of invocation.
I've recently started a project (top secret!) using the new Adobe Integrated Runtime (AIR), Flex and ActionScript 3.0. Coming from a .NET and WPF world. this has been a step in a very different direction. There are a lot of things I don't really love about ActionScript, however it does do its job, and the Adobe AIR deployment strategy (along with its SQLLite database) is pretty damn good.
One of the first things any developer will realize when trying to build a real Rich Internet Application (RIA) in ActionScript is the lack of threading. This makes doing background tasks very difficult. ActionScript, and its class library, works largely with callback methods (either from calling setInterval, using a Timer class, calling a SQLConnection or using the HTTPService or other class to make a data call). From what I can tell, this works much like the Windows message loop, inurrupting synchronous code on your UI thread to process the callback.
While this is great for simple actions (say, a UI that calls a web service or REST service), building a background process (such as a SQL Server synchronization engine) can get complicated. Due to the number of callbacks you'll receive each time you make a request (to SQLConnection or HTTPService), there is a great amount of complexity in writing simple procedual background processes (that don't freeze up the UI).
To better handle this situation, and ensure that your discrete functions run in the proper order (for example, Authenticate -> Get Data), a command pattern in ActionScript will become your best friend. You can string together multiple callbacks, and ensure that the code for these operations stay in one logical class. Furthermore, by using a queue, you can order your commands such that they run synchronously. This provides much more flexibility than the traditional scripting approach in ActionScript.
Unfortunately, I cannot currently provide code samples, as I do not want to compromise the intellectual property of my project, however, I hope that this will help you get an idea of how to best manage your code and synchronous operations in .NET.
Side Note: If you're using WCF I suggest you use the Basic HTTP Binding with Flex, as FlexBuilder gets confused with .NET Web Services
Just a quick note: There is a bug that looks like it won't be fixed for a while in the configuration of the <behaviorExtensions> section of the systm.serviceModel WCF configuration. You may get the ConfigurationErrorsException when adding a new type of behavior (see below):
System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration section handler for system.serviceModel/behaviors: Extension element 'myService' cannot be added to this element. Verify that the extension is registered in the extension collection at system.serviceModel/extensions/behaviorExtensions.Parameter name: element (...\Service.exe.config line 43) ---> System.ArgumentException: Extension element 'wsdlNotice' cannot be added to this element. Verify that the extension is registered in the extension collection at system.serviceModel/extensions/behaviorExtensions.
This is a known bug, but was not accepted by Microsoft as a bug. See bug Microsoft feedback:
https://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=216431
To fix this issue, you will need to use the fully qualified type name, as shown in the sample below:
<add name="myService"
type="Decav.FreeCode.MyServiceBehaviorElement,
Decav.FreeCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
/>
One of the very cool new features in Windows Communication Foundation is the ability to create REST or POX services. Unfortunately, you will quickly find that WebHttpBinding and WebHttpBehavior (both the binding and behavior that are used to pull off the REST operations in WCF) will swallow your exceptions, and worse, leave you with a very generic error message, like the following:
Request Error
The server encountered an error processing the request. See server logs for more details.
This is no good when your client is expecting back XML or a fault code! How to get around this? Implement your own WebHttpBehavior and add a custom error handler. This will let you return a message of your choice. The code below will return a standard SOAP-like fault message. Note that you can use Message.CreateMessage and XmlDocument to create a differently formatted message if you want.
Also, this example wraps ALL exceptions, regardless of their type. The standard WCF way of protecting sensitive server-side information (like stack traces) is to use FaultException, or FaultException<T> in your code, and only show the message if the exception is of one of those types. I would suggest adding this type filter if you care about your server-side intellecual property rights.
FaultingWebHttpBehavior:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel.Description;
6: using System.ServiceModel.Dispatcher;
7: using System.ServiceModel.Channels;
8: using System.Xml;
9: using System.ServiceModel;
10:
11: namespace Decav.FreeCode.ServiceModel
12: { 13: /// <summary>
14: /// A <see cref="WebHttpBehavior"/> that does not attempt to display friendly error messages when an exception occurs
15: /// locating or invoking a service.
16: /// </summary>
17: public class FaultingWebHttpBehavior : WebHttpBehavior
18: { 19: protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
20: { 21: endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
22: endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ErrorHandler());
23: }
24:
25: public class ErrorHandler : IErrorHandler
26: { 27: #region IErrorHandler Members
28:
29: public bool HandleError(Exception error)
30: { 31: return true;
32: }
33:
34: public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
35: { 36: FaultCode faultCode = FaultCode.CreateSenderFaultCode(error.GetType().Name, "http://tempuri.org/net/exceptions");
37: fault = Message.CreateMessage(version, faultCode, error.Message, null);
38: }
39:
40: #endregion
41: }
42: }
43: }
FaultingWebHttpBehaviorElement (this is the configuration element used in the app.config:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel.Configuration;
6:
7: namespace Decav.FreeCode.ServiceModel
8: { 9: /// <summary>
10: /// The configuration element for a <see cref="FaultingWebHttpBehavior"/>.
11: /// </summary>
12: public class FaultingWebHttpBehaviorElement : BehaviorExtensionElement
13: { 14: /// <summary>
15: /// Gets the type of behavior.
16: /// </summary>
17: /// <value></value>
18: /// <returns>A <see cref="T:System.Type"/>.</returns>
19: public override Type BehaviorType
20: { 21: get { return typeof(FaultingWebHttpBehavior); } 22: }
23:
24: /// <summary>
25: /// Creates a behavior extension based on the current configuration settings.
26: /// </summary>
27: /// <returns>The behavior extension.</returns>
28: protected override object CreateBehavior()
29: { 30: return new FaultingWebHttpBehavior();
31: }
32: }
33: }
App.config:
1: <configuration>
2: <system.serviceModel>
3: <services>
4: <service name="Decav.FreeCode.SomeService">
5: <endpoint address=""
6: behaviorConfiguration="WebBehavior"
7: binding="webHttpBinding"
8: contract="Decav.FreeCode.SomeService"/>
9: <host>
10: <baseAddresses>
11: <add baseAddress="http://localhost/Services/SomeService"/>
12: </baseAddresses>
13: </host>
14: </service>
15: </services>
16: <behaviors>
17: <endpointBehaviors>
18: <behavior name="WebBehavior">
19: <faultingWebHttp/>
20: </behavior>
21: </endpointBehaviors>
22: </behaviors>
23: <extensions>
24: <behaviorExtensions>
25: <!-- NOTE: Fully qualified name required, see: https://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=216431 -->
26: <add name="faultingWebHttp" type="Decav.FreeCode.ServiceModel.FaultingWebHttpBehaviorElement, Decav.FreeCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
27: </behaviorExtensions>
28: </extensions>
29: </system.serviceModel>
30: </configuration>