我正在一个ASP.Net MVC网站上工作,但我坚持使用泛型来获取C#代码,以很好地发挥我的观点。
我有一个将模型传递给视图的控制器(到目前为止很好)。模型的类型为IDescribedEnumerable<T>
,对T
有一些约束,其中包括T
从接口(IDescribedModel
)继承的约束。
我可以轻松地编写一个接受IDescribedEnumerable<Country>
的View,只要T
实际上是Country
类型,它就可以工作。
但是,我还要编写一个默认视图,该视图接受IDescribedEnumerable
的<<whatever>>
并将呈现它。这应该是完全可能的。我并不需要总是知道模型的具体类型。通常只要知道它是IDescribedModel
就足够了。
只要我停留在C#中就没有问题。当我不在乎特定的类型时,只需将方法和对象声明为接受<T>
。当我关心时,我声明它们接受Country
。
但:
(1)如果要渲染视图,则必须选择一种类型。我不能只说Inherits="System.Web.Mvc.ViewUserControl<IDescribedEnumerable<T>>"
我必须在<>
之间指定一个现有的类型。 (即使我要从ViewUserControl
继承,也必须将其强制转换为IDescribedEnumerable<<something>>
。
(2)理想情况下,我想说Model在默认View中是IDescribedEnumerable<IDescribedModel>
,在特定实现中是IDescribedEnumerable<Country>
。但是,然后我的控制器需要知道他是要渲染到默认视图还是特定视图。无法简单地将IDescribedEnumerable<Country>
的对象强制转换为IDescribedEnumerable<IDescribedModel>
。 (IIRC在C#4中是可能的,但我使用的是3.5)
所以我该怎么做?我能想到的所有选项都是次优的(我不希望删除泛型并只投射对象,也不希望复制粘贴默认视图65次并保持副本同步,也不希望反射泛滥并创建一个对象基于已知的Type
对象)
最佳答案
在等待一些C#天才以及所有问题的答案的同时,我实现了IEnumerable也使用的技巧:
我向IDescribedEnumerable接口添加了一个方法public IDescribedEnumerable<IDescribedModel> AsIDescribedModels()
,并创建了一个新的类GenericDescribedEnumerable<T> : IDescribedEnumerable<IDescribedModel>
。在我的DescribedEnumerable<T>
类中,创建一个GenericDescribedEnumerable并将其返回。在GenericDescribedEnumerable中,我返回this
完整代码:
public interface IDescribedModel<T> : IDescribedModel{
T original {
get;
}
}
public interface IDescribedEnumerable {
IDescribedEnumerable<IViewModel> AsIViewModels();
}
public interface IDescribedEnumerable<T> : IDescribedEnumerable
where T : IDescribedModel{
IEnumerable<T> GetViewModels();
}
public class DescribedEnumerable<T> : IDescribedEnumerable<IDescribedModel<T>>{
public DescribedEnumerable(IEnumerable<T> enumerable) {}
public IDescribedEnumerable<IViewModel> AsIViewModels() {
return new GenericDescribedEnumerable<T>(/*allProperties*/);
}
public IEnumerable<T> GetViewModels() {
foreach ( T obj in _enumerable ) {
var vm = new DescribedModel<T>( obj);
yield return vm;
}
}
}
public class GenericDescribedEnumerable<T> : IDescribedEnumerable<IViewModel>{
//pass in the constructor everything you need, or create in the
//constructor of DescribedEnumerable<T>
public GenericDescribedEnumerable(/*allProperties*/) {
}
public IEnumerable<IViewModel> GetViewModels() {
foreach ( T obj in _enumerable ) {
var vm = new PlatoViewModel<T>( obj );
yield return vm;
}
}
public IDescribedEnumerable<IViewModel> AsIViewModels() {
return this;
}
}