解决.NET 4与SL 5中的动态类型

时间:2012-09-19 17:18:18

标签: .net generics dynamic

我在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);
        }
    }
}

我必须将此代码移植到WPF应用程序中运行。

当我在WPF应用程序中运行它并在SendCore方法中设置断点时,T不是正确的类型。我只能假设这是因为泛型应该是静态定义的,所以编译器已经创建了它认为在运行时需要的SendCore版本。我猜Silverlight处理的方式不同,因为这段代码在SL中完美运行。

此代码的目标是找到Handlers集合中包含的实现INotificationHandler的任何对象,其中T是传递给Send方法的对象的类型(继承基本Notification类)然后调用Handle(T n )对这些对象的方法。

如何在我的WPF应用中执行此操作?

更新

经过一些额外的测试后,我发现了更多奇特的结果。当我在SendCore方法的第一行设置断点并检查T和通知时,我发现:

  • 智能感知表明T是“GenericNotification” 集合中的合法类。
  • Intellisense表示“通知”是正确的, 强类型类(DataChangedNotification)。
  • DataChangedNotification不会将GenericNotification子类化为任何子类 办法。两个子类通知。
  • 因为T正在解析GenericNotification,试图投射 INotificationHandler&lt; T&gt;的每个处理程序会因为没有而失败 实现INotificationHandler&lt; GenericNotification&gt;

鉴于这个确切的代码适用于Silverlight,一个Console应用程序和另一个WPF应用程序(以及David在LINQpad中的测试),世界上可能会发生什么?

我唯一能想到的是代码实际存在于WPF应用程序引用的类库中。不确定是否重要,因为我在另一个(新的)WPF应用程序中测试了该场景并获得了正确的结果。

2 个答案:

答案 0 :(得分:1)

它适用于我,这是预期的。如果情况不同,我会感到惊讶。

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));
}

此输出

typeof (NA) 
typeof (NB)

答案 1 :(得分:1)

尽管有明显的性格冲突,但我还是赞扬丹尼尔让我继续深入挖掘这个问题。我同时要求删除它,因为我认为它没有为其他任何人提供任何价值。

事实证明,问题确实来自其他地方,并且被一个简单的ToString()重载掩盖了。

第一个问题:我看到(和报告)的行为是另一个开发人员的结果,它有助于向基础Notification类添加ToString覆盖,该类在调试器中显示对象的名称而不是数据类型。这就是为什么在VS中查看'notification'参数会显示预期的类型名称。实际上,传入的对象类型是GenericNotification。

一旦我意识到这种情况正在发生,我就能够打开我们的框架代码(独立构建的独立解决方案),以查看对象的实例化位置。在那里,我发现该文件的.NET版本的实现与Silverlight版本不同。我们使用MEF进行依赖注入,代码的Silverlight版本针对导入的受支持类型列表解析数据类型。 .NET版本使用了switch语句(呃!)。

因此,我更改了.NET版本以使用MEF动态创建对象以帮助解决类型和中提琴!现在一切都按预期工作,压力已经缓解(这是我们软件的关键功能,因此无法正常工作......)。