围绕这一点扯动我的大脑无济于事,想知道是否有人可以提供帮助?
得到一个非常令人沮丧的演员问题,我肯定会得到一个快速的答案,但可能只是由于我对泛型类型推断或其他东西的有限理解而发生。
提前致谢!
方案是向导网站的许多“步骤”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
{
}
测试失败!
[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);
}
问题!
使用Castle.Windsor ,无法投射类型的对象 输入'Company.Namespace.SpecificViewModelBuilder' 'Company.Namespace.Builders.IStepModelBuilder`1 [Company.Namespace.IStepViewModel]'。
Factory Impl如下所示
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;
}
}
注册:
container.AddFacility<TypedFactoryFacility>();
....
container
.Register(
Classes
.FromAssemblyContaining<StepViewModelSelector>()
.BasedOn<StepViewModelSelector>());
container
.Register(
Component
.For<IStepViewModelBuilderFactory>()
.AsFactory(c => c.SelectedWith<StepViewModelSelector>()));
堆栈跟踪:
System.InvalidCastException未被用户代码
处理 HResult = -2147467262 Message =无法转换类型的对象 输入'Company.Namespace.SpecificViewModelBuilder' 'Company.Namespace.IStepModelBuilder`1 [Company.Namespace.IStepViewModel]'。 Source = DynamicProxyGenAssembly2 StackTrace: 在Castle.Proxies.IStepViewModelBuilderFactoryProxy.Create [T](T stepViewModel) 在Tests.Infrastructure.ViewModelBuilderFactoryTests.TestResolution()中 c:\ Project \ Infrastructure \ ViewModelBuilderFactoryTests.cs:第61行 的InnerException:
编辑:IModelBuilder<T>
界面
public interface IModelBuilder<TViewModel>
{
TViewModel Build();
TViewModel Rebuild(TViewModel model);
}
答案 0 :(得分:4)
此处没有显示一个界面,即IModelBuilder<T>
界面,但它是解决问题的关键界面。
我假设它目前的定义如下
public interface IModelBuilder<T> { }
如果您使用自.NET 4以来可用的通用协方差,您可以通过定义这样的界面来解决您的问题:
public interface IModelBuilder<out T> { }
out
修饰符使您的界面协变,这样您就可以从IStepModelBuilder<SpecificStepViewModel>
投射到IStepModelBuilder<IStepViewModel>
。您应该注意,这也会对您的接口施加约束,该约束不允许它定义任何以T
作为参数的方法,但仅作为返回值。
您可以阅读有关Covariance and Contravariance here的更多信息。
修改强>
正如您在评论中提到的,您的界面可能如下所示:
public interface IModelBuilder<T>
{
T Create(T myViewModel);
}
如果不是将T
作为参数传递给Create
,那么您可以通过IStepViewModel
或T
之外的任何其他内容,而不是应该解决你的问题:
public interface IModelBuilder<out T>
{
T Create(IStepViewModel myViewModel);
}
如果没有,那么你的尝试演员阵容真的不应该被允许。
答案 1 :(得分:2)
我认为以下两个定义不兼容
public interface IStepViewModelBuilderFactory
{
IStepModelBuilder<T> Create<T>(T stepViewModel) where T : IStepViewModel;
//... rest of the class definition
}
public class SpecificViewModelBuilder : IStepModelBuilder<SpecificStepViewModel>
{
}
当Create运行时,它会将生成的类型(即SpecificViewModelBuilder
)强制转换为其返回值,即IStepModelBuilder<T>
。
这是不可能的,您可以尝试手动测试它:
class MyTest<T> where T : IStepViewModel
{
void Test()
{
IStepModelBuilder<T> cannotImplicitlyCast = new SpecificStepViewModelBuilder();
}
}
编辑:一些(可能不太好)的想法
可以这样做:
public class ViewModelBuilder<T> : IStepModelBuilder<T> where T : IStepViewModel { } class MyTest<T> where T : IStepViewModel { void Test() { IStepModelBuilder<T> ok= new ViewModelBuilder<T>(); IStepModelBuilder<SpecificStepViewModel> alsoOk = new ViewModelBuilder<SpecificStepViewModel>(); } }
因此您可以专门化工厂,每个特定于一个SpecificStepViewModel