将2个泛型类型从一个转换为另一个

时间:2017-09-20 13:42:55

标签: c# generics casting

我有很多接口,每个接口有2个实现:

public interface Foo{/**/}

public class ModelFoo : Foo {/**/}

public class ViewModelFoo : Foo {/**/}

现在我有一个repositoryInterface和2个带有泛型函数的实现:

    public interface Repository
    {
        ICollection<TModel> GetAll<TModel>();
    }

    public class ModelRepository : Repository
    {
        private IDictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();
        private DbContext context;
        public ICollection<TModel> GetAll<TModel>()
        {
            var implType = typeMapping[typeof(TModel)];
            var ctxSet = context.Set(implType);

            return new EFWrapCollection<TModel>(Enumerable.Cast<object>(ctxSet).ToList());
        }

    }

接口的第一个实现将从数据库加载所有模型。接口类型和具体类型之间的类型映射需要字典 typemapping 。 EFWrapCollection将参数包装为TModel类型。

typemapping 中有以下对:

(typeof(Foo), typeof(ModelFoo)),
(typeof(Bar), typeof(ModelBar)),
...

用法如下:

        var rep = new ModelRepository(context);
        rep.GetAll<Foo>();

这将使用typeparameter Foo 从数据库中返回所有ModelFoo。现在我想做以下事情:

    public class ViewModelRepository : Repository
    {
        private IDictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();
        private Repository repository;
        public ICollection<TModel> GetAll<TModel>()
        {
            var result = repository.getAll<TModel>();
            //now i have the problem that i need a cast 
            //but I dont know hot to achieve it
        }
    }

在此存储库类中还有 typemapping 。此属性包含接口类型和视图模型类型之间的所有映射:

(typeof(Foo), typeof(ViewModelFoo)),
(typeof(Bar), typeof(ViewModelBar)),
.....

强制转换应该是Viewmodeltype的强制转换。我知道如何构建2个具体的类,但是我在这里遇到了问题,这个存储库是通用的,我首先不知道类型。

修改

为什么我需要演员(或映射):

在数据库中只有模型类型的模型,我想将类型模型强制转换(或映射)到类型 ViewModel

1 个答案:

答案 0 :(得分:0)

你正在搅拌苹果和橘子。您不应该跟踪存储库中的类型。存储库应该特定于它使用的类型。

您可以做的是创建一个通用存储库并将其传递给它应该使用的类型。上下文有一个通用的Set<T>方法,您可以利用:

public class Repository<T> 
{
    private DbContext context;
    public ICollection<T> GetAll()
    {            
        var items = context.Set<T>();
        return new EFWrapCollection<T>(items);
    }
}

我不完全确定您使用EFWrapCollection的原因,但我想您有理由。

我猜你现在已经意识到传递EF对象不是一个好主意,除非你适当地管理上下文的生命周期。可以通过许多不同方式处理类型映射。我建议你看一下AutoMapper。您可以创建一个为您映射对象的类,让AutoMapper完成大部分工作,然后为那些不那么直接的属性提供自定义映射:

https://cpratt.co/using-automapper-getting-started/

以下是该链接的快速摘录,为您提供一个想法:

public static class AutoMapperConfig
{
    public static void RegisterMappings()
    {
        AutoMapper.Mapper.CreateMap<ModelFoo, ViewModelFoo>()
            .ForMember(dest => dest.Author,
                       opts => opts.MapFrom(src => src.Author.Name));
    }
}

顺便说一句,如果您遵循约定并在界面前加上字母I(例如IRepository),世界将会欣赏它。它确实使阅读代码更容易。祝你好运!