有没有更好的方法来实现一个可继承的方法,该方法返回一个继承该类类型的对象?

时间:2014-07-21 09:42:51

标签: c# generics inheritance

我正在尝试创建一个基类,它指定一个返回的方法,比如一个自己类型的列表。我希望这个方法在继承类时正常工作,即。返回继承类的列表。

这是我能想到的唯一方法。

public abstract class Base<T>
  where T : Base<T>
{
  public List<T> getList()
  {
    return new List<T>();
  }
}

public class Foo : Base<Foo>
{
}

var foo = new Foo();

// Should return List<Foo>
var fooList = foo.getList(); 

是否有更好的方法不需要Foo继承自身作为类型的基础?说在List<this>中指定Base或类似内容?

正如Groo指出的那样,理想情况下我不希望class Bar : Base<Foo>成为可能。

实际问题我正在尝试解决更新问题:

基本上,我正在尝试使用Entity Framework代码优先的POCO类来返回自己的模型存储,这样我就可以编写一般代码来处理POCO类的验证,并为API保存。

模型存储封装了基本的CRUD操作,以便我们可以覆盖访问方法来执行其他操作,例如隐藏软删除的项目。

在我在验证类和DTO代码(数据传输对象 - 在WSDL API和POCO之间进行转换)中实现相同的getModelStore方法后,我决定这样做。

public abstract class EntityBase<T>
  where T : EntityBase<T>
{
  public abstract ModelStore<T> getModelStore(Repository repository);
}

public class Foo : EntityBase<Foo>
{
  public override ModelStore<Foo> getModelStore(Repository repository);
  {
    // repository.Foo is a Foo ModelStore
    return repository.Foo;
  }
}

var repo = new Repository();
var foo = new Foo();

// Should return the ModelStore for Foo
var fooList = foo.getModelStore(repo); 

2 个答案:

答案 0 :(得分:1)

如果切换到IList界面,则可以在Object上定义扩展方法。 (您不能返回List<>或使用List作为原始类型)

然后,整个应用程序中的每个课程都将提供MakeList方法:

扩展方法:

static class Class1
{
    public static IList MakeList(this Object t)
    {
        var listType = typeof(List<>);
        var finalType = listType.MakeGenericType(t.GetType());
        var instance = Activator.CreateInstance(finalType);
        return (IList)instance;
    }
}

用法:

 Object o = new Object();
 IList list = o.MakeList();
 list.Add(new Object());
 list.Add(new Object());

 MessageBox.Show(list.Count.ToString());

 String s = "";
 IList stringList = s.MakeList();
 stringList.Add("hello");
 stringList.Add("world");

 MessageBox.Show(stringList.Count.ToString());

答案 1 :(得分:1)

我认为主要的问题是这些方法不属于实际实体,而应该由您的存储库服务定位器提供(嗯,它根本不必是定位器,理想情况下你只需要有一个组合根,并通过构造函数注入所有repo依赖项。)

但我们的想法是为crud操作提供一个共同的基础repo接口:

public interface IRepo<T>
{
    T Get(long id);
    IList<T> GetAll();
    void Save(T instance);
    ... 
}

特定实体的特定接口:

public interface IFooRepo : IRepo<Foo>
{
    // additional Foo-specific stuff, if needed
}

这允许您有一个共同的基本抽象实现:

public abstract class BaseRepo<T> : IRepo<T>
{
    // provide default implementations for Load, Save and common stuff
}

然后您的特定存储库继承基类并可选地实现特定方法(请注意,此类不应直接在任何地方实例化,而是通过DI容器实现):

class FooRepo : BaseRepo<Foo>, IFooRepo
{
    // no need to re-implement anything except Foo-specific stuff
} 

最后你有了服务定位器(免责声明:它通常用作单身人士,但实际上不应该这样):

// get the service locator
var repoFactory = GetRepoFactory();

// get the actual repo through DI
var repo = repoFactory.GetRepo<IFooRepo>();

// do stuff
var foo = repo.FindAll();

所以,我的主要评论是我上一个代码段中的GetRepo方法不属于POCO实体。 This article显示了一个带EF的存储库模式示例(跳到“实现通用存储库和工作单元类”部分),虽然我更希望通过DI将repo注入控制器,而不是在控制器构造函数中被new编译。