使用泛型的最佳方式

本文关键字:最佳 方式 泛型 | 更新日期: 2023-09-27 17:58:24

所以我是泛型的新手。但是泛型似乎是减少代码的好方法。下面是场景。我有一个MVC Web API。

http://www.google.com/{controller}/{chartType}/{id} 

注意:id是可选的

我有几种返回类似对象的图表类型:

  1. 小时设备图表
  2. HourlyUsersCharrt
  3. 小时平均处理时间等等

我希望只有一个方法来评估图表类型参数并执行相应的操作。而不是8或10种方法。

如果我的设计需要一些重构,我会接受的。我愿意接受建议。这里的想法是减少一些代码。我不希望在Web API中公开10个方法,然后在另一个类中再公开10个相应的方法。只是显得多余。

一如既往地欢迎您的建议!

API公开的方法:

IEnumerable<T> GetChart(string chartType)
{
    switch(chartType)
    {
        case "DeviceChart":
        return repository.HourlyDeviceChart();
        break;
        case "UserChart":
         return repository.HourlyUsersChart();
         break;
    }
}
//Then the class that handles all the work would look something like the below
IEnumerable<HourlyDeviceChart> HourlyDeviceChart()
{
    // select appropriate items from the queue
    // populate HourlyDeviceChart object
    // add object to list
    // return HourlyDeviceChart list
}
IEnumerable<UserDeviceChart> HourlyUsersChart()
{
    // do more of the same
}

使用泛型的最佳方式

您可以使用这样的泛型:

interface IChart {
    bool IsCharItemNeeded(IChartItem item);
    void AddChartItem(IChartItem item);
}
IEnumerable<T> Charts<T>() where T : new, IChart {
    var res = List<T>();
    foreach (QueueCommand command in MyBigQueue) {
        var chart = new T();
        foreach (IChartItem item in command) {
            if (chart.IsCharItemNeeded(item)) {
                chart.AddChartItem(item);
            }
        }
        res.Add(chart);
    }
    return res;
}

所有图表类型都需要实现通用的IChart接口。where T : new, IChart行提供了一个约束,允许您调用new T();为此,所有图表类还必须实现一个无参数构造函数。

现在你可以像这样使用你的通用代码:

IEnumerable<UserChart> userCharts = Charts<UserChart>();
IEnumerable<DeviceChart> deviceCharts = Charts<DeviceChart>();

如果HourlyUserChartHourlyDeviceChart方法以相同的方式工作,那么dasblinkenlight的答案是好的,您可以有一种通用的方法来填充它们。如果您需要在两种存储库方法中以不同的方式填充它们,则可能需要以下方法:

1)

interface IHourlyChart {
    IEnumerable<IHourlyChart> Create();
}
class HourlyDeviceChart : IHourlyChart 
{
    public IEnumerable<IHourlyChart> Create()
    {
        return repository.HourlyDeviceChart();
    }
}
class HourlyUsersChart : IHourlyChart 
{
    public IEnumerable<IHourlyChart> Create()
    {
        return repository.HourlyUsersChart();
    }
}
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
    return (IEnumerable<T>)new T().Create();
}

2) 或者通过泛型使它具有更强的类型。

interface IHourlyChart<T> where T : IHourlyChart<T> {
    IEnumerable<T> Create();
}
class HourlyDeviceChart : IHourlyChart<HourlyDeviceChart>
{
    public IEnumerable<HourlyDeviceChart> Create()
    {
        return repository.HourlyDeviceChart();
    }
}
class HourlyUsersChart : IHourlyChart<HourlyUsersChart>
{
    public IEnumerable<HourlyUsersChart> Create()
    {
        return repository.HourlyUsersChart();
    }
}
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
    return new T().Create();
}

3) 或者一些反思,这仍然比你的类型检查更好:

IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
    //find necessary method and invoke. may be:
    return repository.GetType()
                     .GetMethods()
                     .Single(x => x.ReturnType == typeof(IEnumerable<T>))
                     .Invoke(repository, new object[0]) as IEnumerable<T>;
}

4) 最糟糕的情况是,在泛型方法内部进行类型检查,但检查类型本身,而不是任何非常脆弱的魔术字符串。

IEnumerable<T> GetChart<T>()
{
    if (typeof(T) == typeof(HourlyDeviceChart))
        return (IEnumerable<T>)repository.HourlyDeviceChart();
    else if (typeof(T) == typeof(HourlyUsersChart))
        return (IEnumerable<T>)repository.HourlyUsersChart();
    // throw;
}

称他们为:

var chartables = GetChart<HourlyUserChart>(); //etc

您应该能够通过使用新接口并对方法GetChart 应用约束来实现这一点

//Interface with a Type parameter to specify the return type of the method
public interface IChart<T>
{
    IEnumerable<T> HourlyChart();
}
//How to implement the interface
public class HourlyDeviceChart : IChart<HourlyDeviceChart>
{
    public static IEnumerable<HourlyDeviceChart> HourlyChart()
    {
        //Do work
    }
}
//Your new method with a constraint applied
IEnumerable<T> GetChart<T>(string chartType) where T : IChart<T>
{
    return T.HourlyChart();
}