【问题标题】:Make generic Type on function as Generic Object将函数上的泛型类型设为泛型对象
【发布时间】:2016-09-06 11:40:53
【问题描述】:

我有一个函数可以在运行时创建多个表的存储库字典,我想要的是使它成为通用的,但我被这个错误困住了..

 public IRepository<TEntity> GetRepository<TEntity>(string TypeName) where TEntity : class 

 {

        Type t = GetInstance(TypeName);
        if (_repositories.Keys.Contains(t))
        {
            return _repositories[t] as IRepository<TEntity>;
        }

        var repository = new Repository<TEntity>(_context);

        _repositories.Add(t, repository);

        return repository;
 }

当我把这个函数称为

 string tn = tt.GetType().FullName;
 Type tttt = GetInstance(tn);
 uu.GetRepository<Object>(tn).Add(tt);

它抛出Exception

实体类型 Object 不是当前上下文模型的一部分。

我怎样才能做到这一点

string tn = tt.GetType().FullName;
Type tttt = GetInstance(tn);
uu.GetRepository<typeof(tt)>(tn).Add(tt);

或其他类型。

【问题讨论】:

  • 你可以通过反射来实现,但有什么意义呢?然后它将忽略泛型类型参数的所有好处。为什么要这样做?
  • 你初始化函数“uu”吗?
  • 你正在使用实体框架?
  • @Evk 我有一个场景,每次我想保存和更新时,动态删除所有动态创建的记录。
  • @LinhTuan,是的,我初始化了 uu

标签: c# generics reflection


【解决方案1】:

如果您只是想知道原则上该怎么做(如果忽略关于您是否应该这样做的问题),那么方法如下:

 string tn = tt.GetType().FullName;
 // get reference to GetRepository<TEntity>
 var genericGet = uu.GetType().GetMethod("GetRepository").MakeGenericMethod(tt.GetType());
 // invoke to get IRepository<TEntity>
 var repository = genericGet.Invoke(uu, new object[] { tn});
 // get IRepository<TEntity>.Add
 var addMethod = repository.GetType().GetMethod("Add");
 // invoke
 addMethod.Invoke(repository, new object[] { tt});

如果你这样做 - 最好让你的 Add 方法接受对象而不是泛型类型参数,因此让你的接口只是 IRepository,而不是 IRepository&lt;T&gt;。然后在存储库中 - 使用上述技术获取对特定 DbSetAdd 方法的引用。

【讨论】:

  • 是的,它的工作,但除此之外还有其他解决方案吗?
  • @user6002727 我记得,实体框架上下文有无类型的 DbSet。类似 context.Set(typeof(YourEntity)) 的东西。然后您可以只使用这些集合(同样,您的 IRepository 将没有通用参数)。
【解决方案2】:

如果你希望它是泛型的,你需要指定一个类型作为泛型参数。 客户端代码必须知道类型,而不仅仅是拥有该类型的实例。

在您的情况下,使用 Object 作为泛型类型参数没有意义,因为这不会为底层框架提供类型推断。这就是引发异常的原因。

另外,在运行时,如果您的解决方案是多线程的,那么您不能在没有额外同步的情况下使用 Dictionary。对于您的任务,我建议您使用 ConcurrentDictionary。

void Main()
{
    var repository = GetRepository<MyEntity1>();
    MyEntity1 instance = repository.Get(1);
}

class MyEntity1
{
}

ConcurrentDictionary<Type, object> repositories = new ConcurrentDictionary<System.Type, object>();

interface IRepository<T>
{
    T Get(int id);
}

class Repository<T> : IRepository<T> where T:new()
{
    public T Get(int id)
    {
        return new T();
    }
}

IRepository<T> GetRepository<T>() where T:new()
{
    return (IRepository<T>)repositories.GetOrAdd(typeof(T), t => new Repository<T>());
}

【讨论】:

  • ConcurrentDictionary.. 的好主意
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-05
  • 2013-01-08
  • 1970-01-01
  • 2013-05-23
  • 1970-01-01
相关资源
最近更新 更多