我正在网上预订网站(航空公司)工作,我想根据某些设置验证用户/客户选择的路线是否有效。现有的代码使用了大量的枚举,我发现自己做了很多if / if else / else来将特定的枚举映射到我想要发生的特定动作。 What I want to do is to write a enum-specific method that would do the mapping for me. Is there any standard way to do this?
这是应用程序代码的简化版本,使用来自真实应用程序的相同类名/枚举值等:
// real app has 9 members, shortened for simplicity's sake
public enum RegionType
{
Station,
Country,
All
}
public enum Directionality
{
Between,
From,
To
}
// simplified version
public class Flight
{
public RegionType RegionType { get; set; }
public RegionType TravelRegionType { get; set; }
public string RegionCode { get; set; }
public string TravelRegionCode { get; set; }
public string RegionCountryCode { get; set; }
public string TravelRegionCountryCode { get; set; }
public Directionality Directionality { get; set; }
}
以下是一些示例用法:
// valid flight
Flight flight = new Flight()
{
RegionCode = "NY",
CountryCode = "JP",
RegionType = RegionType.Station,
TravelRegionType = RegionType.Country,
Directionality = Directionality.Between
};
// these are the station code/country code that user selected
// needs to be validated against the Flight object above
var userSelectedRoutes = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("NY", "JP"),
new KeyValuePair<string, string>("NY", "AU"),
new KeyValuePair<string, string>("JP", "NY")
};
我写的一些代码验证减少了嵌套if / else if / else枚举匹配:
private bool IsRouteValid(Directionality direction, string origin,
string destination, string departure, string arrival)
{
// both departure station and arrival station
if (direction == Directionality.Between)
{
return (origin.Equals(departure, StringComparison.OrdinalIgnoreCase)
&& destination.Equals(arrival, StringComparison.OrdinalIgnoreCase)
|| origin.Equals(arrival, StringComparison.OrdinalIgnoreCase)
&& destination.Equals(departure, StringComparison.OrdinalIgnoreCase));
}
else if (direction == Directionality.From)
{
return (origin.Equals(departure,
StringComparison.OrdinalIgnoreCase));
}
else if (direction == Directionality.To)
{
return (destination.Equals(arrival,
StringComparison.OrdinalIgnoreCase));
}
return false;
}
这是我想要改变的混乱代码:
if (flight.RegionType == RegionType.Station
&& flight.TravelRegionType == RegionType.Country)
{
return userSelectedRoutes.Any(route =>
IsRouteValid(flight.Directionality, route.Key, route.Value,
flight.RegionCode, flight.TravelRegionCode));
}
else if (flight.RegionType == RegionType.Country
&& flight.TravelRegionType == RegionType.Station)
{
return userSelectedRoutes.Any(route =>
IsRouteValid(flight.Directionality, route.Key, route.Value,
flight.CountryCode, flight.RegionCode));
}
else if (flight.RegionType == RegionType.Station
&& flight.TravelRegionType == RegionType.Station)
{
return userSelectedRoutes.Any(route =>
IsRouteValid(flight.Directionality, route.Key, route.Value,
flight.RegionCode, flight.TravelRegionCode));
}
else if (flight.RegionType == RegionType.Station
&& flight.TravelRegionType == RegionType.All)
{
return userSelectedRoutes.Any(route =>
IsRouteValid(flight.Directionality, route.Key, route.Value,
flight.RegionCode, route.Value));
}
else if (flight.RegionType == RegionType.All
&& flight.TravelRegionType == RegionType.Station)
{
return userSelectedRoutes.Any(route =>
IsRouteValid(flight.Directionality, route.Key, route.Value,
route.Key, flight.TravelRegionCode));
}
else if (flight.RegionType == RegionType.All
&& flight.TravelRegionType == RegionType.All)
{
return true;
}
else
{
return false;
}
图例:
RegionCode
=出发站/出发地
TravelRegionCode
=到达站/目的地
Between
=路线必须仅来自指定的出发站和到达站,反之亦然(ex NY-JP或JP-NY)
From
=从特定车站到任何路线(前AU- 全部)
To
=到特定电台的任何路线(前全部 -AU)
如果您注意到,上述所有条件中的.Any
都是相同的,只是略有变化。如果可能,我想减少代码冗余。我使用了KeyValuePair
所以我有一个单一数据类型的出发站和到站。
关于如何让这段代码变得更乱/更漂亮的任何想法?我知道我也硬编码IsRouteValid()
,但我100%确定Directionality
只能有3种可能的组合。另一方面,RegionType
可能有几个组合,如站 - 站,站 - 国家,国家 - 站,国家 - 国家等。
预期输出:
第一条路线的有效/真(NY-JP)
第二条路线无效/错误(NY-AU)
第三条路线的有效/真(JP-NY)[由Directionality
为Between
]
感谢您阅读此长篇查询,并提前感谢您的反馈和建议。
类似帖子:
答案 0 :(得分:4)
按照@MatthiasG的建议,这里是我写完的代码:
private List<KeyValuePair<RegionType, string>>
GetRegionTypeAndValueMapping(Flight flight,
RegionType regionType,
RegionType travelRegionType)
{
var mapping = new List<KeyValuePair<RegionType, string>>();
if(regionType == RegionType.Station)
{
mapping.Add(new KeyValuePair<RegionType, string>
(RegionType.Station, flight.RegionCode));
}
else if(regionType == RegionType.Country)
{
mapping.Add(new KeyValuePair<RegionType, string>
(RegionType.Country, flight.RegionCountryCode));
}
else if(regionType == RegionType.All)
{
mapping.Add(new KeyValuePair<RegionType, string>
(RegionType.All, null));
}
if(travelRegionType == RegionType.Station)
{
mapping.Add(new KeyValuePair<RegionType, string>
(RegionType.Station, flight.TravelRegionCode));
}
else if(travelRegionType == RegionType.Country)
{
mapping.Add(new KeyValuePair<RegionType, string>
(RegionType.Country,
flight.TravelRegionCountryCode));
}
else if(travelRegionType == RegionType.All)
{
mapping.Add(new KeyValuePair<RegionType, string>
(RegionType.All, null));
}
return mapping;
}
我使用List<KeyValuePair<RegionType, string>>
因为Dictionary
不允许重复密钥。我的密钥是RegionType enum
,并且有一段时间出发站和到达站将具有相同的RegionType enum
。 (即站台,国家和全部)。
// Copyright (c) 2010 Alex Regueiro
// Licensed under MIT license, available at
// <http://www.opensource.org/licenses/mit-license.php>.
// Published originally at
// <http://blog.noldorin.com/2010/05/combinatorics-in-csharp/>.
// Version 1.0, released 22nd May 2010.
// modified by moi to be a generator
public static IEnumerable<T[]> GetPermutations<T>(IList<T> list,
int? resultSize,
bool withRepetition)
{
if (list == null)
{
throw new ArgumentNullException("Source list is null.");
}
if (resultSize.HasValue && resultSize.Value <= 0)
{
throw new ArgumentException("Result size must be any
number greater than zero.");
}
var result = new T[resultSize.HasValue ? resultSize.Value : list.Count];
var indices = new int[result.Length];
for (int i = 0; i < indices.Length; i++)
{
indices[i] = withRepetition ? -1 : i - 1;
}
int curIndex = 0;
while (curIndex != -1)
{
indices[curIndex]++;
if (indices[curIndex] == list.Count)
{
indices[curIndex] = withRepetition ? -1 : curIndex - 1;
curIndex--;
}
else
{
result[curIndex] = list[indices[curIndex]];
if (curIndex < indices.Length - 1)
{
curIndex++;
}
else
{
yield return result;
}
}
}
}
好的,我作弊了。 :P我需要一种方法来计算重复的排列,所以我用Google搜索而不是写一个。 (呵呵)我使用排列的原因是为了避免对RegionType
可能具有的所有可能组合进行硬编码。我将Alex Regueiro的方法修改为生成器,以便我可以使用Linq
。有关置换和组合的更新,请参阅this very excellent math stackexchange post。
我修改了IsRouteValid()
来处理值RegionType.All
的{{1}}。
以下是修改后的版本:
null
这是表演时间!
private bool IsRouteValid(Directionality direction, string origin,
string destination, string departure,
string arrival)
{
// ** == All stations/countries
if ((origin == null && departure == "**") &&
(destination == null && arrival == "**"))
{
return true;
}
else if (origin == null && departure == "**")
{
return destination.Equals(arrival, StringComparison.OrdinalIgnoreCase);
}
else if (destination == null && arrival == "**")
{
return origin.Equals(departure, StringComparison.OrdinalIgnoreCase);
}
// both departure station and arrival station
if (direction == Directionality.Between)
{
return (origin.Equals(departure,
StringComparison.OrdinalIgnoreCase) &&
destination.Equals(arrival,
StringComparison.OrdinalIgnoreCase) ||
origin.Equals(arrival,
StringComparison.OrdinalIgnoreCase) &&
destination.Equals(departure,
StringComparison.OrdinalIgnoreCase));
}
else if (direction == Directionality.From)
{
return (origin.Equals(arrival, StringComparison.OrdinalIgnoreCase));
}
else if (direction == Directionality.To)
{
return (destination.Equals(departure,
StringComparison.OrdinalIgnoreCase));
}
return false;
}
我创建了这段代码来演示我如何获得与上述预期结果相同的结果。
RegionType[] allRegionTypes = (RegionType[])
Enum.GetValues(typeof(RegionType));
var validFlights =
GetPermutations<RegionType>(allRegionTypes, 2, true)
.Select(perm => new
{
RegionType = perm.First(),
TravelRegionType = perm.Last()
})
.Where(result => result.RegionType == flight.RegionType &&
result.TravelRegionType ==
flight.TravelRegionType)
.Select(map =>
GetRegionTypeAndValueMapping(flight,
map.RegionType,
map.TravelRegionType));
// same functionality as my previous messy code
// validates all flights selected by user
// it doesn't matter if not all flights are valid
// as long as one of them is
foreach(var validFlight in validFlights)
{
userSelectedRoutes.Any(kvp => IsRouteValid(flight.Directionality,
kvp.Key,
kvp.Value,
validFlight.First().Value,
validFlight.Last().Value))
.Dump("Any Flight");
}
结果:
注意:强>
foreach(var route in userSelectedRoutes)
{
foreach(var validFlight in validFlights)
{
bool condition = IsRouteValid(flight.Directionality,
route.Key,
route.Value,
validFlight.First().Value,
validFlight.Last().Value);
Console.WriteLine(string.Format("{0}-{1} {2}",
route.Key,
route.Value,
condition.ToString()));
}
}
是Linqpad扩展名。