假设我有一个字符串列表,其中的字符串可以具有以下格式:property1
、property1_property2
、property1_property2_property3
。然后,这个字符串列表用于与给定属性集上的串联字符串进行比较:
public List<string> EnabledSettings = new List<string> { "pizza_milk_iceCream", "meatballs_water_slushy", "sallad_tea_candy" };
然后,我们为这个字符串列表的每个变体都有一个类:
public enum Food
{
Pizza,
Meatballs,
Sallad,
Soup
}
public enum Drink
{
Milk,
Beer,
Water,
Tea
}
public enum Dessert
{
IceCream,
Slushy,
Cookies,
Candy
}
public class FeatureOne
{
public List<string> EnabledSettings = new List<string> { "pizza_milk_iceCream", "meatballs_water_slushy", "sallad_tea_candy" };
public bool IsEnabled(Food food, Drink drink, Dessert dessert) => EnabledSettings.Contains($"{food}_{drink}_{dessert}");
}
public class FeatureTwo
{
public List<string> EnabledSettings = new List<string> { "pizza_milk", "meatballs_water", "sallad_tea" };
public bool IsEnabled(Food food, Drink drink) => EnabledSettings.Contains($"{food}_{drink}");
}
现在我想介绍一个通配符,可以将一些属性标记为可选属性,例如property1_*_property3
或property1_property2_*
等。
我该如何处理,以一种更通用的方式?
我一开始是这样的。让每个要素类定义哪些字段适用于每个要素,哪些字段(如果有的话)应该是可选的或不可选的。然后在此基础上创建一个所有可能排列的集合,最终与提供的设置进行比较
public record SettingField(string Value, bool Optional);
public enum Food
{
Pizza,
Meatballs,
Sallad,
Soup
}
public enum Drink
{
Milk,
Beer,
Water,
Tea
}
public enum Dessert
{
IceCream,
Slushy,
Cookies,
Candy
}
public class FeatureOne
{
public List<string> EnabledSettings = new List<string> { "pizza_milk_iceCream", "pizza_beer_*", "meatballs_water_slushy", "meatballs_*_cookies", "sallad_tea_candy" };
public bool IsEnabled(Food food, Drink drink, Dessert dessert)
{
var fields = new List<SettingField>
{
new SettingField(food.ToString(), false),
new SettingField(drink.ToString(), true),
new SettingField(dessert.ToString(), true)
};
var variants = new List<string>(); // All possible permutations based on above given fields
return variants.Any(x => EnabledSettings.Contains(x));
}
}
public class FeatureTwo
{
public List<string> EnabledSettings = new List<string> { "pizza_milk", "meatballs_water", "sallad_tea", "soup_*" };
public bool IsEnabled(Food food, Drink drink)
{
var fields = new List<SettingField>
{
new SettingField(food.ToString(), false),
new SettingField(drink.ToString(), true)
};
var variants = new List<string>(); // All possible permutations based on above given fields
return variants.Any(x => EnabledSettings.Contains(x));
}
}
// Usage
bool featureOneEnabled = new FeatureOne().IsEnabled("pizza_beer_pancakes");
Console.WriteLine(featureOneEnabled) => false // would love to see this true
考虑到可选参数,我不知道如何获得所有可能的排列。我也不知道这是否是解决这一问题的首选方式。我很乐意接受有关的任何建议
编辑
我只强调了一个关键部分,那就是属性是enum类型的。值得一提的是,EnabledSettings列表是在应用程序之外提供的。
您可以使用字符串函数StartsWith
和EndsWith
来实现此目标,而无需更改数据。基本上为开始检查(食物、食物+饮料)创建一个字符串,为结束检查(饮料、饮料+甜点、甜点)创建一条字符串。然后检查设置中的每个字符串,看看它们是否与开始和结束比较字符串都匹配。
public bool IsEnabled(string food, string drink, string dessert)
{
// Check which arguments are wildcards
//
var wildFood = food == "*";
var wildDrink = drink == "*";
var wildDessert = dessert == "*";
// Indicators, all wild cards and when to use StartsWith & EndsWith
//
var allWild = wildFood && wildDrink && wildDessert;
var requiresStartOrEndCheck = !allWild && (wildFood || wildDrink || wildDessert);
// Initialized empty for StartsWith and EndsWith to work without additional conditions
//
var startCheckString = "";
var endCheckString = "";
if (requiresStartOrEndCheck)
{
// Construct the StartsWith string
//
if (!wildFood)
{
startCheckString = food;
if (!wildDrink)
{
startCheckString += "_" + drink;
}
}
// Construct the EndsWith string
//
else
{
if (!wildDrink)
{
endCheckString = "_" + drink;
if (!wildDessert)
{
endCheckString += "_" + dessert;
}
}
else
{
endCheckString = dessert;
}
}
// Check if any settings match using StartsWith and EndsWith strings
//
return EnabledSettings.Any(setting =>
setting.StartsWith(startCheckString) &&
setting.EndsWith(endCheckString)
);
}
// True when all params are wildcards,
// or when the string literal is in the list; otherwise false
//
return allWild || EnabledSettings.Contains($"{food}_{drink}_{dessert}");
}