M05*_*mty 5 .net c# generics casting
围绕着这个我的大脑无济于事,想知道是否有人可以提供帮助?
得到一个非常令人沮丧的演员问题,我肯定会有一个快速回答,但可能只是由于我对泛型类型推断或其他东西的有限理解而发生.
提前致谢!
场景是一个向导站点的"步骤"ViewModel.我正在为每个人创建Builder类,并使用工厂来获取特定的构建器,以获取返回给我的步骤,这是一个IStepViewModel的集合.
public interface IStepViewModelBuilderFactory
{
IStepModelBuilder<T> Create<T>(T stepViewModel) where T : IStepViewModel;
void Release<T>(IStepModelBuilder<T> stepViewModelBuilder) where T : IStepViewModel;
}
public interface IStepViewModel
{
}
public interface IStepModelBuilder<TStepViewModel> : IModelBuilder<TStepViewModel> where TStepViewModel : IStepViewModel
{
}
public class SpecificViewModelBuilder : IStepModelBuilder<SpecificStepViewModel>
{
}
public class SpecificStepViewModel: StepViewModel
{
}
public abstract class StepViewModel : IStepViewModel
{
}
Run Code Online (Sandbox Code Playgroud)
失败的测试!
[Test]
public void TestResolution()
{
var factory = this.container.Resolve<IStepViewModelBuilderFactory>();
IStepViewModel viewModel = new SpecificStepViewModel();
var builder = factory.Create(viewModel); // Here
Assert.That(builder, Is.Not.Null);
}
Run Code Online (Sandbox Code Playgroud)
问题!
无法将类型为"Company.Namespace.SpecificViewModelBuilder"的对象强制转换为'Company.Namespace.Builders.IStepModelBuilder`1 [Company.Namespace.IStepViewModel]'.
Factory Impl如下使用Castle.Windsor
public class StepViewModelSelector : DefaultTypedFactoryComponentSelector
{
protected override Type GetComponentType(System.Reflection.MethodInfo method, object[] arguments)
{
var arg = arguments[0].GetType();
var specType = typeof(IModelBuilder<>).MakeGenericType(arg);
return specType;
}
}
Run Code Online (Sandbox Code Playgroud)
注册:
container.AddFacility<TypedFactoryFacility>();
....
container
.Register(
Classes
.FromAssemblyContaining<StepViewModelSelector>()
.BasedOn<StepViewModelSelector>());
container
.Register(
Component
.For<IStepViewModelBuilderFactory>()
.AsFactory(c => c.SelectedWith<StepViewModelSelector>()));
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪:
System.InvalidCastException未由用户代码处理
HResult = -2147467262 Message =无法将类型为"Company.Namespace.SpecificViewModelBuilder"的对象强制转换为'Company.Namespace.IStepModelBuilder`1 [Company.Namespace.IStepViewModel]'.Source = DynamicProxyGenAssembly2 StackTrace:at Castle.Proxies.IStepViewModelBuilderFactoryProxy.Create [T](T stepViewModel)at tests.Infrastructure.ViewModelBuilderFactoryTests.TestResolution()in c:\ Project\Infrastructure\ViewModelBuilderFactoryTests.cs:line 61
InnerException:
编辑:IModelBuilder<T>界面
public interface IModelBuilder<TViewModel>
{
TViewModel Build();
TViewModel Rebuild(TViewModel model);
}
Run Code Online (Sandbox Code Playgroud)
有一个界面你没有在这里展示,它是界面IModelBuilder<T>,但它是解决你的问题的关键界面。
我假设它目前是这样定义的
public interface IModelBuilder<T> { }
Run Code Online (Sandbox Code Playgroud)
如果您使用自 .NET 4 起可用的通用协方差,您将能够通过如下定义接口来解决您的问题:
public interface IModelBuilder<out T> { }
Run Code Online (Sandbox Code Playgroud)
修饰符out使您的接口协变,这将允许您从 转换IStepModelBuilder<SpecificStepViewModel>为IStepModelBuilder<IStepViewModel>。您应该注意,这也对您的接口施加了限制,不允许它定义任何作为T参数的方法,而只能作为返回值。
您可以在此处阅读有关协方差和逆变的更多信息。
编辑
正如您在评论中提到的,您的界面可能如下所示:
public interface IModelBuilder<T>
{
T Create(T myViewModel);
}
Run Code Online (Sandbox Code Playgroud)
如果您可以传递或其他任何内容而不是T作为参数传递给,那么这应该可以解决您的问题:CreateIStepViewModelT
public interface IModelBuilder<out T>
{
T Create(IStepViewModel myViewModel);
}
Run Code Online (Sandbox Code Playgroud)
如果不是,那么你的尝试铸造确实不应该被允许。