无法在 WPF 设计器中将“Castle.Proxies.XProxy”类型的对象转换为“X”类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20865810/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:21:45  来源:igfitidea点击:

Unable to cast object of type 'Castle.Proxies.XProxy' to type 'X' in WPF Designer

c#wpfvisual-studio-2013nsubstitutexaml-designer

提问by Todd Bowles

I've recently discovered the very useful design time attributes from Blend for a WPF component, which (among other things) allows you to set a DataContext only at design time. Awesome!

我最近发现了来自 Blend 的非常有用的 WPF 组件设计时属性,它(除其他外)允许您仅在设计时设置 DataContext。惊人的!

Combined with the DesignInstance attribute, you can set a type to be automatically created and bound to during design time, allowing you to use the Visual Studio Designer with some context as to what your WPF component will actually look like at run time. Its really nice, and I wish it hadn't taken me so long to discover.

结合 DesignInstance 属性,您可以将类型设置为在设计时自动创建和绑定,从而允许您使用带有一些上下文的 Visual Studio 设计器,了解 WPF 组件在运行时的实际外观。它真的很好,我希望我没有花这么长时间去发现。

Obviously, because I'm here and not living it up in programmer heaven I've encountered a problem while using these design time attributes.

显然,因为我在这里而不是在程序员天堂里生活,所以我在使用这些设计时属性时遇到了问题。

I've created a design time wrapper around one my ViewModels, which has a parameterless constructor (so it can be created by the designer). Inside its constructor, it uses NSubstitute to mock out all of the dependencies injected into the ViewModel it inherits from.

我在我的 ViewModels 周围创建了一个设计时包装器,它有一个无参数的构造函数(因此它可以由设计者创建)。在其构造函数中,它使用 NSubstitute 来模拟注入到它继承自的 ViewModel 中的所有依赖项。

Using this design time class in the designer results in an error much like the following:

在设计器中使用此设计时类会导致如下错误:

Unable to cast object of type 'Castle.Proxies.XProxy' to type 'X'.

Unable to cast object of type 'Castle.Proxies.XProxy' to type 'X'.

(With the X being replaced with one of my injected dependencies).

(将 X 替换为我注入的依赖项之一)。

You can use the following minimal set of code to reproduce the problem.

您可以使用以下最少的代码集来重现该问题。

Create a WPF Application in VS2013 targeting .NET Framework 4.5.1 (it might happen in previous versions too, I don't know) with the following files in it.

在 VS2013 中创建一个面向 .NET Framework 4.5.1 的 WPF 应用程序(它也可能发生在以前的版本中,我不知道),其中包含以下文件。

View.xaml

查看.xaml

<Page 
    x:Class="DesignTimeNSubstituteIssue.Views.View"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:DesignTimeNSubstituteIssue_Views_DesignTime="clr-namespace:DesignTimeNSubstituteIssue.Views.DesignTime"
    mc:Ignorable="d" 
    d:DataContext="{d:DesignInstance Type=DesignTimeNSubstituteIssue_Views_DesignTime:DesignTimeViewModel, IsDesignTimeCreatable=True}">
    <Grid>
        <TextBlock Text="{Binding Message, FallbackValue=Design_Time_Message_Failed_Using_Fallback}"/>
    </Grid>
</Page>

ViewModel.cs

视图模型.cs

using DesignTimeNSubstituteIssue.Services;

namespace DesignTimeNSubstituteIssue.ViewModels
{
    public class ViewModel
    {
        public ViewModel(XDependency dependency)
        {
            _Dependency = dependency;
        }

        private readonly XDependency _Dependency;
        public string Message { get; protected set; }
    }
}

DesignTimeViewModel.cs

DesignTimeViewModel.cs

using DesignTimeNSubstituteIssue.Services;
using DesignTimeNSubstituteIssue.ViewModels;
using NSubstitute;

namespace DesignTimeNSubstituteIssue.Views.DesignTime
{
    public class DesignTimeViewModel : ViewModel
    {
        public DesignTimeViewModel()
            : base(Substitute.For<XDependency>())
        {
            Message = "This is a Design Time message.";
        }
    }
}

XDependency.cs

XDependency.cs

namespace DesignTimeNSubstituteIssue.Services
{
    public interface XDependency
    {

    }
}

Compile, close and reopen the solution and open View.xaml in the designer. It will work just fine.Then, close the designer, rebuild solution and open View.xaml in the designer again, and you will get the following error:

编译、关闭并重新打开解决方案,然后在设计器中打开 View.xaml。它会工作得很好。然后,关闭设计器,重建解决方案,再次在设计器中打开View.xaml,会出现如下错误:

Unable to cast object of type 'Castle.Proxies.XDependencyProxy_1' to type 'DesignTimeNSubstituteIssue.Services.XDependency'.

Unable to cast object of type 'Castle.Proxies.XDependencyProxy_1' to type 'DesignTimeNSubstituteIssue.Services.XDependency'.

When this error occurs, the designer stops using the specified DesignTimeViewModel, and falls back to having no DataContext at all.

发生此错误时,设计器将停止使用指定的 DesignTimeViewModel,并退回到根本没有 DataContext。

The only way to fix this is to close and reopen the solution.

解决此问题的唯一方法是关闭并重新打开解决方案。

I suspect I know what is happening, but I don't know why its happening or how to fix it.

我怀疑我知道发生了什么,但我不知道为什么会发生或如何解决它。

I think that on the first compile the designer is obtaining a reference to the assembly and caching it. When the second compile occurs, the assembly is rebuilt and is mostly the same, but the NSubstitute proxy is regenerated with a new suffix (like Castle.Proxies.XDependencyProxy_2or something) which wasn't in the first assembly, so the designer doesn't know that that proxy actually implements the XDependency interface. This is purely conjecture on my part.

我认为在第一次编译时,设计者正在获取对程序集的引用并将其缓存。当第二次编译发生时,程序集被重建并且大部分是相同的,但是 NSubstitute 代理使用第一个程序集中没有的新后缀(例如Castle.Proxies.XDependencyProxy_2或其他东西)重新生成,因此设计人员不知道该代理实际上实现了 XDependency 接口。这纯粹是我的猜测。

I can create a workaround by not using NSubstitute, and manually mocking the dependencies, but I'm interested to see if someone can shed some light on the subject.

我可以通过不使用 NSubstitute 并手动模拟依赖项来创建解决方法,但我很想知道是否有人可以对这个主题有所了解。

采纳答案by Todd Bowles

It looks as though both my original project AND minimal reproduction project do not version the assembly correctly, meaning the designer doesn't know that it needs to reload the assembly (because the new one is exactly the same version as the old one). Changing the assembly version to include an autogenerated version number appears to fix the problem.

看起来好像我的原始项目和最小复制项目都没有正确地对程序集进行版本控制,这意味着设计者不知道它需要重新加载程序集(因为新的与旧的版本完全相同)。更改程序集版本以包含自动生成的版本号似乎可以解决问题。