Reputation: 5494
I have the following code working in Silverlight 5:
public void Send(Notification notification)
{
// Because the variable is passed as Notification, we have to trick the
// type-inference feature of the runtime so the message will be sent using
// the actual type of the object.
// Using the dynamic keyword, we can convert the type of the object passed
// to the Send method.
// This allows subscribers to register for messages using the generic interface.
dynamic stronglyTypedNotification = Convert.ChangeType(notification,
notification.GetType(),
CultureInfo.InvariantCulture);
SendCore(stronglyTypedNotification);
}
private void SendCore<T>(T notification)
where T : Notification
{
foreach (var handlerFactory in Handlers)
{
var handler = handlerFactory.Value as INotificationHandler<T>;
if (handler != null)
{
handler.Handle(notification);
}
}
}
I have to port this code over to run in a WPF application.
When I run it in my WPF application and set a breakpoint inside the SendCore method, T is not the correct type. I can only assume this is because generics are supposed to be staticly defined so the compiler has created the version of SendCore it thinks it will need at runtime. I guess Silverlight handles this differently because this code works perfectly in SL.
The goal of this code is to locate any of the objects contained in the Handlers collection that implement INotificationHandler where T is the type of the object passed to the Send method (subclassing the base Notification class) then call the Handle(T n) method on those objects.
How can I do this in my WPF app?
UPDATE
After some additional testing, I am finding more peculiar results. When I set a breakpoint on the first line of the SendCore method and inspect T and notification, I find:
Given that this exact code works in Silverlight, a Console application and another WPF application (as well as David's test in LINQpad), what in the world could be going on?
The only thing I can think of mentioning is that the code actually exists in a Class Library that is referenced by the WPF application. Not sure that matters because I tested that scenario in another (new) WPF application and had the correct results.
Upvotes: 1
Views: 127
Reputation: 5494
Despite the obvious personality clash, I am giving credit to Daniel for pushing me to continue digging deeper and deeper into the problem. I am at the same time requesting that it be removed as I see it providing no value for anyone else.
As it turns out, the problem did originate elsewhere and was being masked by a simple ToString() overload.
The first problem: The behavior I was seeing (and reporting) is the result of another developer helpfully adding a ToString override to the base Notification class that displays the name of the object in the debugger instead of the data type. This is why looking at the 'notification' parameter in VS displayed the expected type name. In reality, the type of object being passed in was GenericNotification.
Once I realized this was happening, I was able to open our framework code (separate solution built independently) to see where the object was instantiated. There I found that the .NET version of the file was implemented differently than the Silverlight version. We use MEF for dependency injection and the Silverlight version of the code was resolving the data type against an imported list of supported types. The .NET version used a switch statement (ugh!).
So, I changed the .NET version to dynamically create the object using MEF to help resolve the type and viola! Everything is now working as expected and the pressure has been eased (this is a critical function of our software, so having it not work...).
Upvotes: 1
Reputation: 174309
It works for me and that's expected. I would have been surprised if it was different.
void Main()
{
Send(new NA());
Send(new NB());
}
public class Notification {}
public class NA : Notification {}
public class NB : Notification {}
public void Send(Notification notification)
{
dynamic stronglyTypedNotification
= Convert.ChangeType(notification,
notification.GetType(),
CultureInfo.InvariantCulture);
SendCore(stronglyTypedNotification);
}
public void SendCore<T>(T notification) where T : Notification
{
Console.WriteLine(typeof(T));
}
This outputs
typeof (NA)
typeof (NB)
Upvotes: 1