C# 在C中转换为泛型类型#

C# 在C中转换为泛型类型#,c#,generics,C#,Generics,我们在C#中有一个抽象泛型类,非常像这样: public abstract class Repository<T> where T: Entity { public abstract void Create(T t); public abstract T Retrieve(Id id); //etc. } m_dicMapper.Add(typeof(Event), typeof(EventRepository)); //and so on for

我们在C#中有一个抽象泛型类,非常像这样:

public abstract class Repository<T>
    where T: Entity
{
    public abstract void Create(T t);
    public abstract T Retrieve(Id id);
    //etc.
}
m_dicMapper.Add(typeof(Event), typeof(EventRepository));
//and so on for a few other repository classes.
public Repository<T> GetRepository<T>(T t)  
    where T : Entity  
{  
    Type tyRepo = m_dic[t.GetType()];  
    Repository<T> repo = (Repository<T>)Activator.CreateInstance(tyRepo);  

    return repo;  
}
Event ev = new Event();
dynamic e = ev;
var repo = registry.GetRepository(e);
然后,当需要创建实体
e
时,例如:

//retrieve the repository type for the correct entity type.
Type tyRepo = m_dicMapper[e.GetType()];
//instantiate a repository of that type.
repo = Activator.CreateInstance(tyRepo);
//and now create the entity in persistence.
repo.Create(e);
问题是,上面代码中的
repo
是什么类型?我想将它声明为generic
Repository
type,但显然C#不允许我这么做。以下任何一行都无法编译:

Repository repo;
Repository<T> repo;
Repository<e.GetType()> repo;
repo;
仓库回购;
仓库回购;
我可以将其声明为
var
,但是我无法访问
Create
存储库实现的其他方法。我希望能够使用泛型类来泛型地使用存储库!但我想我做错了什么


所以我的问题是,我可以用什么样的编码和/或设计方法来解决这个问题?谢谢。

我个人建议使用单独的单例类封装对字典的访问,然后封装字典的getter和setter,类似于
RepositoryStore

我建议将
Dictionary
更改为
Dictionary
,然后在
RepositoryStore
中处理转换;是这样吗

更新(使用
Type
s和
Lazy
) 如果您使用的是.NET4,那么就可以充分利用
Lazy
类,并将字典类型更改为
IDictionary
。我已经修改了我的原始答案,以反映这可能是如何工作的:

class RepositoryStore
{
    private IDictionary<Type, Lazy<object>> Repositories { get; set; }

    public RepositoryStore()
    {
        this.Repositories = new Dictionary<Type, Lazy<object>>();
    }

    public RepositoryStore Add<T, TRepo>() where TRepo : Repository<T>
    {
        this.Repositories[typeof(T)] = new Lazy<object>(() => Activator.CreateInstance(typeof(TRepo)));
        return this;
    }

    public Repository<T> GetRepository<T>()
    {
        if (this.Repositories.ContainsKey(typeof(T)))
        {
            return this.Repositories[typeof(T)].Value as Repository<T>;
        }

        throw new KeyNotFoundException("Unable to find repository for type: " + typeof(T).Name);
    }
}
类存储库
{
专用IDictionary存储库{get;set;}
公共存储库()
{
this.Repositories=newdictionary();
}
public RepositoryStore Add(),其中TRepo:Repository
{
this.Repositories[typeof(T)]=newlazy(()=>Activator.CreateInstance(typeof(TRepo));
归还这个;
}
公共存储库GetRepository()
{
if(this.Repositories.ContainsKey(typeof(T)))
{
将此.Repositories[typeof(T)].值返回为Repository;
}
抛出new-KeyNotFoundException(“找不到类型:“+typeof(T).Name)”的存储库);
}
}
然后使用非常简单

var repositoryStore = new RepositoryStore()
// ... set up the repository store, in the singleton?

Repository<MyObject> myObjectRepository = repositoryStore.GetRepository<MyObject>();
myObjectRepository.Create(new MyObject());
var repositoryStore=new repositoryStore()
// ... 在singleton中设置存储库存储?
Repository myObjectRepository=repositoryStore.GetRepository();
创建(新建MyObject());

如果在编译时知道所需的类型,则可以使用泛型。例如,您可以执行以下操作:

m_dictMapper.Add<Event, EventRepository>();

…

var repo = m_dictMapper.Get<Event>(); // repo is statically typed as Repository<Event>
var e = repo.Create(); // e is Event


另外,我发现您的
Create()
方法非常混乱。具有该名称的方法应该返回已创建的实例,而不是对现有实例执行某些操作。

经过多次尝试,我找到了解决方案。基本上,问题是我有一个集合(各种存储库),我想从抽象的角度类似地处理这些集合,但它们不是从公共类继承的;它们只是泛型类的特殊具体化,但这并没有多大帮助。除非

我们使用@Richard建议的repository registry类,其方法如下:

public abstract class Repository<T>
    where T: Entity
{
    public abstract void Create(T t);
    public abstract T Retrieve(Id id);
    //etc.
}
m_dicMapper.Add(typeof(Event), typeof(EventRepository));
//and so on for a few other repository classes.
public Repository<T> GetRepository<T>(T t)  
    where T : Entity  
{  
    Type tyRepo = m_dic[t.GetType()];  
    Repository<T> repo = (Repository<T>)Activator.CreateInstance(tyRepo);  

    return repo;  
}
Event ev = new Event();
dynamic e = ev;
var repo = registry.GetRepository(e);
因为,尽管e是一个
事件
,但就通用解析而言,它在编译时作为一个
实体
解析。你需要这样的东西:

public abstract class Repository<T>
    where T: Entity
{
    public abstract void Create(T t);
    public abstract T Retrieve(Id id);
    //etc.
}
m_dicMapper.Add(typeof(Event), typeof(EventRepository));
//and so on for a few other repository classes.
public Repository<T> GetRepository<T>(T t)  
    where T : Entity  
{  
    Type tyRepo = m_dic[t.GetType()];  
    Repository<T> repo = (Repository<T>)Activator.CreateInstance(tyRepo);  

    return repo;  
}
Event ev = new Event();
dynamic e = ev;
var repo = registry.GetRepository(e);
这就解决了我的问题


感谢@Richard建议创建一个单独的存储库注册表,感谢所有提供反馈的人
至于您的
m_dicMapper
,repo只是一种
类型
。。。这里有问题吗?您需要创建类型为
repo
的对象,或者存储实际对象的数组,而不是它们的类型。repo的类型为。而且它没有create方法。也许你希望你的字典值是
Repository
类型?最重要的是:你想要一个类型映射,然后使用你得到的类型来实例化一个新实例,还是想要在映射中保存一个存储库实例?如果是这样,问题归结为:我怎么能拥有(我可以吗?)类似于
map
的东西,其中
typeof(T)=Type
?@Jason我不这么认为。如果是那样的话,那么使用
e.GetType()
@svick:谢谢。我不知道设计时的类型;我只知道
e
是一个实体,但它的具体类型将决定存储库的具体类型。因此,问题就来了。你不能将与
e
一起工作的方法设置为泛型吗?那就意味着你知道类型。@svick:问题是,我不知道类型。我只知道它是从实体派生出来的,但它可以是二十多个类中的任何一个。@svick:还有,第一行的m_dictMapper是什么类型的?谢谢你的解决方案。不过,有一个问题。我不想将字典从更改为,因为我想存储到存储库类的映射,而不是存储库实例的映射。使用您的方法会迫使我从一开始就实例化所有存储库,这是不好的。我宁愿保留一个类的映射,并根据需要实例化它们。有什么解决办法吗?我已经稍微更新了我的答案,使用了
Lazy
,而不是
object
;这应该有类似的预期效果。谢谢。我会尽快尝试。我已经尝试过你的方法,但我无法让它工作。它似乎依赖于在编译时知道实体
e
的类型,正如我所说,事实并非如此。换句话说,
GetRepository()
不能是泛型的,因为调用它时无法指定类型。很抱歉