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



简言之,我希望有一些方法可以实现这种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对象上创建一个新列表。在这个精心设计的例子中,这没什么大不了的,但是这个god-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实现了两次,因为类型不会影响实际的方法签名
  • List<T> All<T>中的第二个T是冗余的
  • List<Car> All<Car>中,Car只是T的另一种编写方式,并不引用实际的Car

这是我第一次深入研究C#中的正确泛型——这可能吗?

这不是分部类的用途。分部类的具体用途是在多个文件之间分割类的功能。

当使用泛型时,目的是定义通用的core功能,然后这些功能可以被多个具体类型重用。

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

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 { }

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

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

我会考虑用接口IRepoItem约束回购项目本身(CarTruck等),并使回购成为非泛型类,All<T>()方法是泛型的,使用对项目类型的约束All<T>()可以返回该接口,例如:All<T>() where T : IRepoItem

示例代码:

using System.Collections.Generic;
namespace IRepo
{
class Program
{
static void Main(string[] args)
{
var repo = new Repo();
var carList = repo.All<Car>(); // ok
var truckList = repo.All<Truck>(); // ok
//var bananas = repo.All<Banana>(); // compiler error
}
}
public class Repo
{
public List<T> All<T>() where T : IRepoItem
{
return new List<T>();
}
}
public interface IRepoItem { }
public class Car : IRepoItem { }
public class Truck : IRepoItem { }
public class Banana { } // not an IRepoItem
}

最新更新