我正在一个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;
    }
}

10-06 01:36