是否可以通过输入类型重载泛型方法?

时间:2016-06-09 18:40:22

标签: c# .net

简而言之,我希望有一些方法可以实现这种API风格:

Repo repo = new Repo();
List<Car> cars = repo.All<Car>();
List<Truck> trucks = repo.All<Truck>();

我有一个Repo对象,可以从数据库中检索对象。目前它的工作原理如下:

Repo repo = new Repo();
List<Car> cars = repo.Cars.All();
List<Truck> trucks = repo.Trucks.All();

Repo类的位置是:

class Repo {
    List<Car> Cars = new CarRepo();
    List<Truck> Trucks = new TruckRepo();
}

CarRepoTruckRepo各包含:

interface IRepo<T> {
    List<T> All();
}

class CarRepo : IRepo<Car> {
    List<Car> All() => new List<Car>() { };
}
// Same for TruckRepo

不幸的是,如果我想在此模式中添加新的车辆集合,我需要在Repo对象上创建一个新列表。在这个人为的例子中,这没什么大不了的,但是这个上帝 - Repo对象在具有许多子回购的应用程序中可能会变得非常大。我更喜欢的是直接Repo类工具All

这是我最接近的:

interface IRepo<T>
{
    List<T> All<T>();
}

partial class Repo {}

partial class Repo : IRepo<Car>
{
    public List<Car> All<Car>() => new List<Car>() { };
}

partial class Repo : IRepo<Truck>
{
    public List<Truck> All<Truck>() => new List<Truck>() { };
}

// Usage:
Repo repo = new Repo();
List<Car> cars = repo.All<Car>();

这会将All<>方法添加到Repo,但由于一些我不知道解决方案的问题,它甚至无法编译。

  • All<>针对Repo实施两次,因为类型不会影响实际的方法签名
  • T中的第二个List<T> All<T>是多余的
  • List<Car> All<Car>中,Car只是撰写T的另一种方式,而不是指实际的Car

这是我第一次在C#中钻研适当的仿制药 - 这是否可能?

3 个答案:

答案 0 :(得分:5)

这不是要使用的部分类。 partial类的具体用法是在多个文件之间拆分类的功能。

使用泛型时,目的是定义通用的 核心 功能,然后可以由多种具体类型重复使用。

因此,您应该为每种类型创建一个新的具体存储库类。

interface IRepo<T>
{
    List<T> All<T>();
}

class CarRepo : IRepo<Car>
{
    public List<Car> All<Car>() => new List<Car>() { };
}

class TruckRepo : IRepo<Truck>
{
    public List<Truck> All<Truck>() => new List<Truck>() { };
}

public class Truck { }
public class Car { }

答案 1 :(得分:1)

也许这样的方法可以帮助你:

interface IRepo<T>
{
    IEnumerable<T> All();
}

class Repo : IRepo<Car>, IRepo<Truck>
{
    public IEnumerable<T> All<T>()
    {
        if (this is IRepo<T>)
            return (this as IRepo<T>).All();

        throw new NotSupportedException();
    }

    IEnumerable<Truck> IRepo<Truck>.All() => new List<Truck>();  //Implemented explicitly

    IEnumerable<Car> IRepo<Car>.All() => new List<Car>();        //Implemented explicitly
}

执行此操作,您可以根据需要实施尽可能多的IRepo,并进行repo.All<Type>()之类的调用。

这样的事情:

var repo = new Repo();

var trucks = repo.All<Truck>();
var cars = repo.All<Car>();
var motors = repo.All<Motorcycle>(); //throws NotSupportedException

答案 2 :(得分:1)

我会考虑使用接口Car约束repo项本身(TruckIRepoItem等),并使Repo成为{{1的非泛型类方法是通用的,使用项All<T>()类型的约束可以返回到该接口,例如:All<T>()

示例代码:

All<T>() where T : IRepoItem