使用泛型的最佳方式
本文关键字:最佳 方式 泛型 | 更新日期: 2023-09-27 17:58:24
所以我是泛型的新手。但是泛型似乎是减少代码的好方法。下面是场景。我有一个MVC Web API。
http://www.google.com/{controller}/{chartType}/{id}
注意:id是可选的
我有几种返回类似对象的图表类型:
- 小时设备图表
- HourlyUsersCharrt
- 小时平均处理时间等等
我希望只有一个方法来评估图表类型参数并执行相应的操作。而不是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>();
如果HourlyUserChart
和HourlyDeviceChart
方法以相同的方式工作,那么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();
}