如何在泛型 class 的具体 class 中引用类型

how to reference the Type in the Concrete class of a generic class

我找到了以下示例,对此我有一个跟进问题。

stack overflow question

问题的现有代码是

 public interface IRepository<T> where T : EntityObject
 {
    RepositoryInstructionResult Add(T item);
    RepositoryInstructionResult Update(T item);
    RepositoryInstructionResult Delete(T item);
 }

 public class Repository<T> : IRepository<T> where T : EntityObject
 {
    virtual RepositoryInstructionResult Add(T item)
    { //implementation}
    virtual RepositoryInstructionResult Update(T item);
    { //implementation}
    virtual RepositoryInstructionResult Delete(T item);
    { //implementation}
  }

public class BarRepository : Repositorybase<Bar>
 {
    public override RepositoryInstructionResult Update(Bar item);
    {
       //Call base method if needed
       //Base.Update(item);

       //implement your custom logic here
    }
  }

我想做的是将 Update 方法更改为

public class BarRepository : Repositorybase<Bar>
 {
    // T is of Type Bar
    public override RepositoryInstructionResult Update(T item);
    {
       //implement your custom logic here
    }
  }

问题:有没有办法将 BarResposity : Repositorybase<Bar> 中的泛型类型暴露给 BarRepository 中的方法?

在构建具体内容时寻找“搜索和替换”的更好替代方法 class(例如,将 BarRespository 复制为 FooRepository,并将所有引用从 Bar 更改为 Foo)。我宁愿只在一个地方更改类型。

(edit) 用法需要保持为

var obj = new BarRepository();

恕我直言,任何 GENERIC 存储库都是浪费时间,但如果您决定使用它,这有什么问题

public class BarRepository<T> : Repository<Bar> where T : class
{
    public override void Update(Bar item)
    {

    }
    
    public  void Update(T item)
    {
     
    }
}

更新

它看起来很奇怪,但既然 OP 想要它,您也可以创建此代码

public class BarRepository<T> : Repository<Bar> where T : Bar
{
    public override void Update(Bar item)
    {
        Console.WriteLine("it is Bar");
    }
    // T is of Type Bar
    public void Update(T item)
    {
          Console.WriteLine("it is T");
    }
}

测试

public class Bar { }
public class NoBar { }

var barRep= new BarRepository<Bar>();

barRep.Update(new Bar()); // "it is T"

var noBarRep= new BarRepository<NoBar>(); // ERROR!

更新 2

因为如果你想要

var rep = new BarRepository();

var result= rep.Update(new Bar());

你可以按照你已经做过的方式去做

public class BarRepository : Repositorybase<Bar>
 {
    public override RepositoryInstructionResult Update(Bar item);
    {
   
       return base.Update(item);
    }
  }

PS

如果你还不满意,请看我回答的开头,忘记通用存储库。像最专业的开发人员一样使用自定义的。

请注意,如果您无论如何要覆盖所有 Add/Update/Delete,您可以在 RepositoryBase 中将它们设为抽象,然后 vs 建议是您的朋友:

如果所有具体 classes 之间存在共享逻辑,您可以将其放在抽象 class 中并改写抽象受保护的方法。

编辑: op 要求提供可以做到这一点的代码。这应该可以工作。但是如果你想要一个新的具体实现,你现在必须创建 2 classes

public class BarRepository<T> : RepositoryBase<T> where T : Bar
{
    public override int Add(T item)
    {
        throw new NotImplementedException();
    }
    public override int Update(T item)
    {
        throw new NotImplementedException();
    }
    public override int Delete(T item)
    {
        throw new NotImplementedException();
    }
}

public class BarRepository : BarRepository<Bar>
{

}

另外,如果 classes 是如此相似以至于复制粘贴和替换就足够了,也许逻辑不应该在单独的 classes 中而是在通用的 class 中?你能举个 2 class 的例子吗?

编辑 2:另一个肮脏的技巧是使用 lambda,尽管我个人不知道是否会这样做:

public abstract class RepositoryBase<T>
{
    public Func<T, int> Add { get; protected set; }
    public Func<T, int> Update { get; protected set; }
    public Func<T, int> Delete { get; protected set; }
}
public class BarRepository : RepositoryBase<Bar>
{
    public BarRepository()
    {
        Add = i => 6;
        Update = i => 7;
        Delete = i => 8;
    }
}

有点hack,但是您可以使用using别名来定义实体类型:

 using MyType = Bar;

 public class BarRepository : Repositorybase<MyType>
 {
    public override RepositoryInstructionResult Update(MyType item);
    {
   
       return base.Update(item);
    }
  }

现在,当您复制到 Foo.cs 时,您只需将 using 指令更改为

 using MyType = Foo;

但是,我会尝试尽可能多地重用通用代码,因为仅通过查看方法根本不清楚 MyType 是什么。 find.replace 定义自定义操作的新存储库类型没有错 - 您只是想将重复次数保持在最低限度。