Sharing code between Silverlight and .NET
Currently, a Silverlight Class Library cannot be loaded by the server side project and vice versa. This despite there being very close parity in the BCL on either side. Now, I agree that sharing actual business logic between client and server is a bit of an edge case, but when it comes to data interchange, having a single codebase for you DTOs would be very useful.
Luckily, with a bit of trickery, this can be accomplished, although it would be nice if Visual Studio could just do this for you. I've done this on two different projects, once creating DTOs that were then serialized using the JSON DataContract serializer and other other time using the normal XmlSerializer.
The basic trick is this: Two separate projects can point at the same source code files (and even the integrated source control providers will play along with this game). However, playing by Visual studio rules you can't just create two projects in the same directory because the wizards treats ProjectName == DirectoryName. Here's how you get around this:
- Create a new server side Class Library, say Server.Dto.
- Create a new Silverlight Class Library, say Silverlight.Dto.
- Clean out that default Class.cs and update both to have the same default namespace Foo.Dto. Your solution should look something like this:
- Now, right-click on Silverlight.Dto and choose Remove
- Close Visual Studio
- Rename the Silverlight.Dto/Properties directory to Silverlight.Dto/Silverlight.Properties
- Copy Silverlight.Properties and Silverlight.Dto.csproj to the Server.Dto directory
- Now, and this is the tricky bit, open Silverlight.Dto.csproj in some text-editor (notepad works, but don't try to use Visual studio for this) and change the line
<Compile Include="Properties\AssemblyInfo.cs" />
to
<Compile Include="Silverlight.Properties\AssemblyInfo.cs" />
- Re-open your solution, right-click on the Solution in the Solution Explorer and choose Add -> Existing Project..., browse to Server.Dto and select Silverlight.Dto.csproj
- Add your first shared class FooDto.cs to Server.Dto (if you add it on the Silverlight side, you need to clean up a bunch of using statements).
- Select Silverlight.Dto and click the Show All Files button at the top of the panel. You should see FooDto.cs in Silverlight.Dto now
- Right-click FooDto.cs and choose Include in Project, like this:
- Voila, you now have two assemblies referencing the same code so that you can use the same code on both client and server sides. Just repeat the last couple of steps for every new class you want to share.
I know you could use a Web Service from within Silverlight and would automatically generate you the proxy on the client side. And I'd recommend that if your payload is dynamic. However, if your payload is generated occasionally by a server side program or periodic service, this methods lets you create Dto's, serialized in your favorite manner that can be consumed as static files with WebClient.
Labels: .net, c#, silverlight
VS2k5 & WPF
After having tried a bunch of different iterations to get the WPF tools installed for VS2k5, here's what finally worked"
- Install .NET 3.0
- Install Visual Studio Tools for WCF/WPF
- And only then install .NET 3.0 SP1
Talk about annoying dependencies.
Labels: .net, wpf
More Deferred Execution Fun: foreach and delegation scope
This is closely related to my
last post on deferred execution gotchas and its basically more "if you inline delegated code, you may easily overlook scope side-effects". This time it's about dealing with foreach and using the local each item for deferred execution.
public void SpawnActions()
{
foreach (ActionContext context in contexts)
{
int id = context.Id;
Action<int> callback =
(workerNumber) =>
{
Console.WriteLine("{0} Id: {1}/{2}", workerNumber, id, context.Id);
};
ThreadPool.QueueUserWorkItem(new WaitCallback(FutureExecute), callback);
}
}
public void FutureExecute(object state)
{
int id = worker++;
Action<int> callback = state as Action<int>;
Thread.Sleep(500);
callback(id);
}
The output looks like this:
0 Id: 0/9
1 Id: 1/9
2 Id: 2/9
3 Id: 3/9
4 Id: 4/9
5 Id: 5/9
6 Id: 6/9
7 Id: 7/9
8 Id: 8/9
9 Id: 9/9
So while the foreach scope variable context is kept alive for the deferred execution, it turns out that foreach re-uses the variable on each pass through the loop and therefore when the Action
is later executed, each one has a reference to the last context. So what we need to do is create a true local variable for context so that the lambda's scope can hold on to the reference we want.
foreach (ActionContext context in contexts)
{
int id = context.Id;
// locally scoped variable
ActionContext c2 = context;
Action<int> callback =
(workerNumber) =>
{
Console.WriteLine("{0} Id: {1}/{2}", workerNumber, id, c2.Id);
};
ThreadPool.QueueUserWorkItem(new WaitCallback(FutureExecute), callback);
}
And now our results are a bit more what we expected:
0 Id: 0/0
1 Id: 1/1
2 Id: 2/2
3 Id: 3/3
4 Id: 4/4
5 Id: 5/5
6 Id: 6/6
7 Id: 7/7
8 Id: 8/8
9 Id: 9/9
Labels: .net, c#, delegate, foreach, lambda
The dangers of deferred execution
I recently wrote about
Action & Func, which along with Lambda expression let you do easy inline callbacks like this:
Utility.ActionDownloader.Download(
Configuration.GetAssetUri(dto.Url),
(Downloader d) =>
{
FloatContainer c = (FloatContainer)XamlReader.Load(d.ResponseText);
c.Initialize(dto);
});
i.e. I can call a downloader and inline pass it a bit of code to execute once the download completes. But the catch of course is that looking at the code, and following the usual visual tracing of flow hides the fact that
c.Initialize(dto) doesn't get called until some asynchronous time in the future. Now, that's always been a side-effect of delegates, but until they became anonymous and inline, the visual deception of code
that looks like it's in the current flow scope but isn't wasn't there.
What happened was that I needed my main routine to execute some code after FloatContainer was initialized, and by habit i created an Initialized event on FloatContainer. Of course this was superfluous, since my lambda expression called the synchronous Initialize, i.e my action could be placed inline after that call to c.Initialize(dto) and be guaranteed to be called after initialization had completed.
This scenario just meant I created some superfluous code. However, I'm sure as I use lambda expression more, there will be more pitfalls of writing code that doesn't consider that its execution time is unknown, as is the state of the objects tied to the scope of the expression.
This last bit about objects tied to the expression scope is especially tricky and I think we will see some help in terms of Immutable concepts weaving their way into C# 3.x or 4.0, as the whole functional aspect of lambda expressions really work best when dealing with objects that cannot change state. Eric Lippert's been laying the groundwork in a number of posts on the subject and while he constantly disclaims that his ponderings are not a roadmap for C#, I am still going to assume that his interest and recognition of the subject of Immutables will have some impact in a future revision of the language. Well, I at least hope it does.
Labels: .net, c#, delegate, lambda
Action & Func: Never write another delegate
With lambda expressions in C#, the Func
generic delegate and it's variations have been getting a lot of attention. So naturally, you might think that the lambda syntax is just a shortcut for creating anonymous delegates, whether they return values or not.
First let's look at the evolution of delegates from 1.1 to now. Delegates, simply are the method equivalent of function pointers. They let you pass a method call as an argument for later execution. The cool thing (and a garbage collection pitfall) is that a delegate creates a lexical closure, i.e. the delegate carries with it the object that the method gets called on. For garbage collection this means that a delegate prevents an object from being collection. That's why it's important to unsubscribe from those events you subscribed to.
But I digress. Let's define a delegate that returns an Integer and a method that matches that delegate:
delegate int IntProducerDelegate();
public int x = 0;
public int IntProducer()
{
return x++;
}
With the original .NET 1.0 syntax we'd create the delegate like this:
IntProducerDelegate p1 = new IntProducerDelegate(IntProducer);
Now we can call p1() and get an integer back, and since it's closure, each time we call p1() the originating objects x increases as does our return value.
Then, in .Net 2.0 we got anonymous delegates.
IntProducerDelegate p2 = delegate { return IntProducer(); };
// or with IntProducer's action inlined...
IntProducerDelegate p3 = delegate { return x++; };
This got rid of the need to create a method just to pass along a closure that manipulated our object at a later time. The other thing that anonymous delegates re-inforce is that delegates just care about signature. IntProducerDelegate can get assigned any delegate that takes no argument and returns an int. That sounds like a perfect scenario for a delegate and in .NET 3.5, we got just that, a set of generic delegates called Func. Using Func, we quickly get to our lambda expression replacing the original delegate syntax like this:
// create a new Func delegate just like the IntProducerDelegate
IntProducerDelegate p3 = new Func<int>(IntProducer);
// which means that we don't need IntProducerDelegate at all anymore
Func<int> p4 = delegate { return x++; };
// and the anonymous delegate can also be shorthanded with a lambda expression
Func<int> p5 = () => { return x++; };
// which says, given that we take no argument "()", execute and return the following "return x++;"
However, before there ever was Func, .Net 2.0 introduced the generic delegate Action, which is a natural counterpart to Func, encapsulating a method that does not return anything. Following through the example of the producer, we'll create a consumer like:
delegate void IntConsumerDelegate(int i);
public void IntConsumer(int i)
{
Console.WriteLine("The number is {0}", i);
}
Now following the same evolution of syntax we get this:
IntConsumerDelegate c1 = new IntConsumerDelegate(IntConsumer);
IntConsumerDelegate c2 = new Action<int>(IntConsumer);
Action<int> c3 = delegate(int i) { Console.WriteLine("The number is {0}", i); };
Action<int> c4 = (i) => { Console.WriteLine("The number is {0}", i); };
So lambda syntax can be used to create either a Func or an Action. And that also means that we never have to explicitly need to create another delegate, being able to use a variation of these two generic delegates as our arsenal for storing lambda expressions of all kinds.
Labels: .net, c#, delegate, lambda
TDD & you can't test what you can't measure
Recently I've been dealing with a lot of bug fixing that I can't find a good way to wrap tests around. Which is really annoying, because it means that as things get refactored these bugs can come back. These scenarios are almost always UI related, whether it's making sure that widgets behave as expected, or monitoring the visual state of an external application I'm controlling (Live For Speed, in this case). What all these problems have in common is that the recognition of a bug existing can only be divined by an operator, because somewhere there is lack of instrumentation that could programatically tell the state I'm looking for. And to paraphrase the old management saying, "You can't test what you can't measure".
My best solution is the usual decoupling of business logic from UI. Make everything a user can do an explicit function of your model and now you can test the functions with unit tests. At least you business logic is solid, even if your presentation gets left in the cold. And depending on your UI layer, a lot of instrumentation can still be strapped on. WinForms controls are generally so rich that nearly everything you would want to test for you can probably query from the controls. But things that you can test and see within a second may be a lot of lines of code to test programatically and of course go right out the window when you refactor your UI. And if your trying to test the proper visual states of a DataGridView and its associated bindings, then you're in for some serious automation pains.
I know that business logic is the heart of the application, but presentation is what people interact with and if it's poor, then it doesn't matter how kick ass your back end is. So for the time being that means that UI takes a disproportionate amount of time to run through its possible states and it's something I would like to handle more efficiently.
Labels: .net, c#, LFS, tdd
Observable event subscription
The other day I was trying to create an explicit interface implementation of an event and ran into a snag. Now I've done many explicit interface implementations before, but, I guess, never of an event, because I'd not seen the below compiler error before:
An explicit interface implementation of an event must use property syntax
Huh? I did some searches on that error and the best reference was this page. I had long forgotten that the whole += and -= was closely related to how properties work. But instead of using get and set you can create your own logic for subscribe and unsubscribe using add and remove.
As Oliver points out on his blog, it does mean that your event just becomes a facade and you still need another event that actually is being subscribed to. So for that explicit interface implemenation you'd get something like this:
interface IFoo
{
event EventHandler FooHappened;
}
class SomeClass : IFoo
{
private event EventHandler internal_FooHappened;
public event EventHandler IFoo.FooHappened
{
add { internal_FooHappened += value; }
remove { internal_FooHappened -= value; }
}
private void OnFooHappened()
{
if( internal_FooHappened != null )
{
internal_FooHappened(this,EventArgs.Empty);
}
}
}
Now this is really an edge case, imho. But the same syntactic trick does allow for something else that's pretty cool, i.e. being able to be notified when someone subscribes to your event. I've had it happen a number of times, where it would have been useful to take some action on subscription. Maybe the event needs some extra resource, that you don't want to initialize unless someone needs it. It may even be that the real event handler is that resource. So now you can use the above syntax and put extra logic inside of the add to initialize that resource, like this:
class SomeClass
{
SomeResource myResource;
public event EventHandler FooHappened
{
add
{
if( myResource == null )
{
myResource = new SomeResource();
}
myResource.FooHappened += value;
}
remove
{
myResource.FooHappened -= value;
if( myResource.FooHappened == null )
{
myResource.Dispose();
myResource = null;
}
}
}
} Labels: .net, c#, events, explicit interface implementation
A generic asynchronous INotifyPropertyChanged helper
The other day I was lamenting
what I consider to be an omission in Data-binding's responsibilities, i.e. the lack of invocation of an
INotifyPropertyChanged PropertyChanged event on the appropriate UI thread. Instead,
INotifyPropertyChanged implementors are expected to be updated only on the UI thread in order to work.
I figured I should be able to throw a proxy between the actual INotifyPropertyChanged implementor and the binding, and have this proxy be instantiated with awareness of the observing form. Thus the proxy could do the invocation on the UI thread and still let me use INotifyPropertyChanged without creating a dependency on knowing that the object was being observed by a UI element. That line of thought lead to worked as a static proxy, that I had to create by hand. Once I switched to Castle's Dynamic Proxy, it didn't work anymore, the event somehow being swallowed along the way.
I also considered looking at creating my own BindingContext but that didn't bear fruit either. It was then that I realized that I didn't need to create a proxy that matched my source object, since data binding didn't care what it bound to, as long as it had the dataMember it was being told about. I started down a path of creating a wrapper class using Reflection.Emit when I further reasoned that even the dataMember that's exposed doesn't have to match the one of the data source. This opened the door to just using dynamic property invocation and a simple generic helper class emerged:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
namespace FullMotion.Helpers
{
/// <summary>
/// A helper class for creating a binding on an object that may be changed
/// asynchronously from the bound UI thread.
/// </summary>
public class AsyncBindingHelper : INotifyPropertyChanged
{
/// <summary>
/// Get a binding instance that can invoke a property change
/// on the UI thread, regardless of the originating thread
/// </summary>
/// <param name="bindingControl">The UI control this binding is added to</param>
/// <param name="propertyName">The property on the UI control to bind to</param>
/// <param name="bindingSource">The source INotifyPropertyChanged to be
/// observed for changes</param>
/// <param name="dataMember">The property on the source to watch</param>
/// <returns></returns>
public static Binding GetBinding( Control bindingControl,
string propertyName,
INotifyPropertyChanged bindingSource,
string dataMember )
{
AsyncBindingHelper helper
= new AsyncBindingHelper(bindingControl,bindingSource,dataMember);
return new Binding(propertyName,helper,"Value");
}
Control bindingControl;
INotifyPropertyChanged bindingSource;
string dataMember;
private AsyncBindingHelper( Control bindingControl,
INotifyPropertyChanged bindingSource,
string dataMember )
{
this.bindingControl = bindingControl;
this.bindingSource = bindingSource;
this.dataMember = dataMember;
bindingSource.PropertyChanged
+= new PropertyChangedEventHandler(bindingSource_PropertyChanged);
}
void bindingSource_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null && e.PropertyName == dataMember)
{
if (bindingControl.InvokeRequired)
{
bindingControl.BeginInvoke(
new PropertyChangedEventHandler(bindingSource_PropertyChanged),
sender,
e );
return;
}
PropertyChanged(this, new PropertyChangedEventArgs("Value"));
}
}
/// <summary>
/// The current value of the data sources' datamember
/// </summary>
public object Value
{
get
{
return bindingSource.GetType().GetProperty(dataMember)
.GetValue(bindingSource,null);
}
}
#region INotifyPropertyChanged Members
/// <summary>
/// Event fired when the dataMember property on the data source is changed
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
To use this class, simply replace this:
myLabel.DataBindings.Add("Text", myDataSource,"MyProperty");
with this:
myLabel.DataBindings.Add(
AsyncBindingHelper.GetBinding(myLabel, "Text", myDataSource,"MyProperty") );
The one tricky thing about this is that it may cause uncollectable references. We're creating an instance of AsyncBindingHelper behind the scenes that sets up an event handler on our binding source. Which means we can't get rid of that event subscription. Theoretically, once the binding control goes out of scope, the helper should also go out of scope, relinquishing the reference it holds on the binding source.
The other thing that would be simple to do is to turn this helper into an Extension Method on INotifyPropertyChanged, once I move my code over to Orcas. That way creating an asynchronous binding on an instance of INotifyPropertyChanged would become even cleaner and straight forward.
Labels: .net, c#, Data Binding, INotifyPropertyChanged, Reflection.Emit
INotifyPropertyChanged and Cross-thread exceptions
I'm currently reading
Adam Nathan's
WPF Unleashed. It's a good read and has me ready for doing some serious WPF work. However, the things I have on my plate are a already Windows Forms and can't really take a late in the project UI architecture change, so my production use of WPF will have to wait a little longer. I originally thought WPF was horribly over-engineered, but going through Adam's book, the decisions that led to the sometimes odd APIs make sense. It's clear that toolability of Xaml, separation of logic and code and allowing the greatest amount of design without any code are what led to the cumbersome manual C# syntax. But once you mix in Expression Blend, you won't be doing any of those nasty things unless you're writing your own custom controls. Ok, this is a lovely tangent, but hardly the subject of this entry...
While reading I came across INotifyPropertyChanged. Since it's meant for binding in general, I thought this might be a perfect fit for a design issue I was having on a WinForms project. Basically, I have an object that manages a native process and can get manipulated via remoting. The UI in the program really just exists for status updates on this management object. The solution for keeping the UI in sync was either a timer that polled the object's properties or create an event for each property change, manually subscribe to them in the form and update the UI that way. However, INotifyPropertyChanged provided a simple methodology for tracking changes in all objects and let the implementing object be used for data-binding. I'm usually against code that uses strings to reference object members, like data-binding is wont to do, since it falls outside of compile-time checking and is liable to get out of sync in refactoring, but data-binding is convenient and so prevalent in .NET, that I decided to use it for this.
Implementing INotifyPropertyChanged on my object was dead simple and the syntax for binding my labels to property changes was even easier. Perfect, another process simplified. Or so I thought. What happened next is what I personally would describe as a bug or at least mis-feature in data binding, but at least according to the docs, it's by design.
INotifyPropertyChangeddoes not work for asynchronous operations
What happened was this: I made changes to my object via the remoting proxy and my client UI died with an InvalidOperationException(Cross-thread operation not valid...). On it's face this is straight forward: My object is on a background thread, being manipulated by remoting. My UI is on the UI thread, so tweaking the UI by the background thread is a no-no. This is confirmed by the MSDN documentation which says:
If your data source implements the INotifyPropertyChanged and you are performing asynchronous operations you should not make changes to the data source on a background thread. Instead, you should read the data on a background thread and merge the data into a list on the UI thread.
That to me is bad advice and a lazy way of saying that data binding doesn't do its due diligence on binding operations. Why? Well, the purpose of something like INotifyPropertyChanged is Separation of Concerns, decoupling the observer of the property data from the observable object. But what the above says is that the observed object is responsible for knowing how it might be observed.
The logical thing is that your INotifyPropertyChanged object neither knows nor should care that it's data may be used to update the UI on another thread. The party that's responsible for that bit of house-keeping is the one that does the actual updating of the UI controls, i.e. data-binding. Data-binding is intimately aware of the UI object it's tied to and it's the one that isactually updating the UI in response to an incoming event. It seems logical and practical that it would do the necessary check on Control.InvokeRequired and perform said invoke. Instead telling you that your object better live on the UI thread is just not very good advice, imho.
Where does that leave us?
Well, even if the business object wanted to invoke on the UI thread, it couldn't unless it was aware of the UI thread, and that once again violates the Separation of Concerns that should exist between business logic and UI. So that leaves us with two options: a) change the way binding works to the way described above or b) put a proxy between the binding and the INotifyPropertyChanged implementor.
Since you can assign a new BindingContext to a control, a) may be an option, and it's one I'm going to investigate next. However for the time being, going down the path of b) was simpler.
I hardcoded a proxy for my business object, had it implement INotifyPropertyChanged as well and created a factory that would take both the form and the proxied object to create a new proxy. The proxy then subscribed to the proxied PropertyChanged event and used its reference to the form to make sure it was invoked on the UI thread.
public class MyBusinessObject : INotifyPropertyChanged
{
[...]
public int MyProperty
{
get { [...] }
}
[...]
}
public class MyBusinessObjectProxy : INotifyPropertyChanged
{
Control bindingControl;
MyBusinessObject bindingSource;
private MyBusinessObjectProxy(Control bindingControl, MyBusinessObject bindingSource)
{
this.bindingControl = bindingControl;
this.bindingSource = bindingSource;
bindingSource.PropertyChanged += new PropertyChangedEventHandler(bindingSource_PropertyChanged);
}
void bindingSource_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
if (bindingControl.InvokeRequired)
{
bindingControl.BeginInvoke(new PropertyChangedEventHandler(bindingSource_PropertyChanged), sender, e);
return;
}
PropertyChanged(this, new PropertyChangedEventArgs(e.PropertyName));
}
}
public int MyProperty
{
get { return bindingSource.MyProperty; }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
That works beautifully, but since it's specific to my particular object that's a lot of hand-coding. This whole proxy/adapter scheme screams for a generic implementation. But now we need to intercept requests of properties we may not know exist. Back in the perl days (and most dynamic languages feature this as well) I would have just created an AUTOLOAD method that catches all calls to methods that don't exist. It didn't seem like this would exist in C#, since that violates the whole compile time checking of a static language like C#. But there is Reflection, so maybe I was wrong. However, after checking with Oren Eini, who clearly has a much greater understanding of how to do funky things with C#, it turns out that such a facility indeed does not exist.
Next up was creating a proxy object that could be cast to the original type and handle the binding calls that way. I built a prototype based on Castle's Dynamic Proxy, which proxied the properties just fine, but apparently the event subscription doesn't work, because the proxy's PropertyChanged event never acquired any subscribers. So until I can figure out what happens to events on Dynamic Proxy, I'm stuck with statically built proxies.
In the meantime, I guess I'm going to look at BindingContext to see if the problem can be solved generically at that end, while trying to figure out why Dynamic Proxy isn't working. Stay tuned.
Labels: .net, c#, Castle, cross-thread exception, Data Binding, Dynamic Proxy, INotifyPropertyChanged
LFSLib.NET 0.13b released
Now with full patch X goodness!
This version of LFSLib.NET takes advantage of all the new features of Live For Speed S2 0.5X (as well as the X2 test patch additions). The new version can be found here and the release notes are here. There is a new binary distro with a winforms Tester app, which is located here, but in general the tester app does not provide full coverage and will eventually be replaced with a better example and test harness. The highlights are:
- TCP connections (more on that below)
- Multiple InSim Connections at the same time
- Custom Button system
- Lots more tracking events
I've run it through its paces, but as InSim coverages is getting quite large now and I don't have an automated test suite, I cannot claim to have full test coverage. In general, if something doesn't work, assume it's LFSLib.NET, not LFS and let me know. Contact me via the email on the left, blog comments or posting about LFSLib.NET on the LFS programmer forums (which I monitor fairly consistently).
Moving the documentation to SandCastle has taken more time than I hoped. The new doc system is now a dynamic web application and provides a (IMHO) much improved interface thanks to Dave Sexton's excellent DocProject. This has required my moving of the docs off this server to a new host, so the docs and future information for LFSLib.NET from now on lives at lfs.fullmotionracing.com.
About TCP & UDP
A quick note about TCP and UDP in 0.13b. You can have up to 8 TCP connections, but you still can only have one UDP connection. When you configure the
InSimHandler, set the
UseTCP flag in the
configuration. In general, you want to make sure that you do NOT set
ReplyPort. Why? As soon as you set reply port, LFS will send
RaceTrackNodelap (IS_NLP) and
RaceTrackMultiCarInfo (IS_MCI) events via that port on UDP. LFSLib.NET handles that transparently, but since you've now crossed over into UDP land, you have now used up that one UDP connection that is available and things will get wonky if you connect another InSimHandler with the same settings, even though you thought you were just using TCP.
Labels: .net, c#, InSim, LFS, LFSLib.NET, live for speed, OutGauge, OutSim
How to do Control Flow via Polymorphism
Let's say you have n objects implementing an interface. Call these message, implementing IMessage. Each message may cause a different action when given to another object, the receiver. Sounds like the perfect scenario for Polymorphism. Create a method Handle() for each of the n messages specifying the concrete type in the signature. Now, let's say you receive that message from a MessageFactory and, obviously, that factory hands you the message via the interface. So here's the pseudo code:
public interface IMessage
{
}
public class MessageA : IMessage
{
}
public class MessageB : IMessage
{
}
public class Receiver
{
public void Handle(MessageA msg)
{
}
public void Handle(MessageB msg)
{
}
}
public class MessageFactory
{
public static IMessage GetMessage()
{
}
}
Now, how do you pass this message off to the appropriate Handle() version? You can't just call Handle() with your message because you message is actually an IMessage not the concrete type. I can think of three workarounds and don't like any of them. Is there another way, or is this just a limitation of C#? In the meantime, here are the three ways I can think of solving this:
The Switch
The traditional way, use if/else or switch to examine the incoming object and dispatch it. Just create a method Handle(IMessage msg) and have it dispatch each to the proper Handle(). Traditional, simple. But as n increases it becomes less and less readable and dispatch is now a runtime decision. It could just fail, if you overlooked a concrete class.
The Reflection
At runtime examine the actual type of the message and then inspect your receiver to dynamically invoke the appropriate methods. No worries about maintaining the code or readability. It's just magic... but runtime magic which may yet fail if you overlooked a concrete class.
The Self-Dispatcher
There is probably a named pattern that goes with this approach. It shares some aspects with the Visitor pattern (that's what inspired me actually), but I don't know what this pattern is actually called. The idea is that each message doesn't get passed to the receiver but passes itself. I.e. it calls the appropriate method. For this to work, we add a method to our interface:
public interface IMessage
{
void Dispatch(Receiver receiver);
}
public class MessageA : IMessage
{
public void Dispatch(Receiver receiver)
{
receiver.Handle(this);
}
}
This works perfectly. After getting the message from the factory, you just call msg.Dispatch(receiver). Since each message implements its own dispatch for itself, we get compile time checking. Yay. But we basically copy and paste the Dispatch() method into every message class and we can't factor it into a common base-class, because that would break the flow control again. So it achieves the ends I'm after, but I don't like the implementation.
What other options are there?
Labels: .net, c#, control flow, polymorphism
Silverlight, Moonlight and a true VM for your browser
Considering my
previous rant about RIA platforms, I'm a bit slow out the gate with my
Silverlight comments. But there was a lot to digest before making half-baked comments.
While I was at MEDC, Mix07 was going on next door. I didn't even hear the cool Silverlight announcements until I got back from Vegas. But now that i've played with it, it's exactly what I had hoped for (minus a disconnected use model): We have a true VM to code against on the client side. That means the full breadth of .NET languages to control the reduced WPF presentation layer, plus with the DLR true scripting support at near-compiled performance.
As I expected, there was no linux support announced by MS and neither does it appear that they've opened a channel to the mono team. But Miguel de Icaza has addressed this issue independently with the Moonlight project and listening to the chatter on the dev list and following the wiki updates, that project is getting serious attention. I may even be better this way. I think a firefox plug-in coming from the mono team would be more willingly installed by linux users than something coming directly from MS.
We'll have to see how much more of the WPF set of Xaml gets supported by Silverlight as 1.1 moves to beta and RTM. Obviously, the way custom controls are done is not ideal right now--the way properties are acting against implementationRoot (haven't gotten deep enough to understand why it's not using the DependencyObject/Property pattern) and the shadowing of inherited properties just make for a strange experience compared to Controls in WPF, Windows Forms or even ASP.NET. Hopefully that morphs into a better model as we move along. If nothing else, the development of the promised suite of UI controls provide internal motivation to refine the model. Not that I think that DependencyObject/Property is an elegant coding pattern (at least not until that legwork moves into code generation).
But while everyone is busy committing the same UI crimes that many Flash developers have been guilty of for years, I think the real significance of Silverlight is not it's Xaml and rich media support. In my opinion the most amazing feat of Silverlight is its DOM interoperation. The Silverlight VM is accessible in both directions, complete with object serialization across boundaries. This means you can have managed code attached to DOM events, and managed code modifying the DOM itself or calling javascript in the page. With a minimum of glue, you could move all your code inside of Silverlight and even if you don't care about C# et al., you'd at least get a much higher performance javascript out of the deal. Then add the rich communications infrastructure and the hinted at socket level networking in future versions and suddenly you can have very fast, very interactive web applications that could be truly stateful and have better event handling for asynchronous operation etc.
Right now, you need some 1x1 pixel Silverlight object that everything gets channeled through, but MS has already promised that that dependency is going away. So what you really have is a VM and rich framework addressable with bytecode compiled from a huge number of potential languages in the browser. Whether you use that VM to drive your HTML, Silverlight's presentation layer or even the canvas tag is up to you. It's what I hoped that the browser manufacturers would do themselves, but as a plug-in, the chance of this capability becoming ubiquitous is even better, imho.
Silverlight 1.1 alpha is clearly a very early peek into the tech, but it works just great already. I'm curious what it will look like by the time it's an official release. And I certainly hope that by that time, MS has given the disconnected, self-hosted option some consideration. After all, when competing with Flash/Flex, one shouldn't ignore Apollo.
Labels: .net, c#, javascript, moonlight, ria, silverlight, wpf