我很难弄清楚如何做到这一点,基本上我有一个应用程序使用枚举来确定这个人所在的建筑物,然后是他们所属的部门。
根据此人所在的部门,可以添加不同的组。我想这样做,以便该方法只执行一次,直到他们关闭并重新打开应用程序,有点像白名单。
问题在于,当想要使用泛型方法时,Enumerations似乎是一个巨大的痛苦。
我能够找到一种方法来实现这一点,使用通用静态字典,但它看起来很糟糕,我不知道是否有我忽视的东西或者更容易做我想要的东西。
#include <iostream>
#include <any>
void* enabler = nullptr;
template <
typename R, typename F,
typename std::enable_if<std::is_same<typename std::remove_cv<R>::type, std::any>::value>::type*& = enabler,
typename... Args>
std::any call(F fn, Args&&... args) {
return fn(std::forward<Args>(args)...);
}
std::any func(int i)
{
std::cout<<i<<"\n";
return std::any(1);
}
void func2(int i)
{
std::cout<<i<<"\n";
}
int func3(int i)
{
std::cout<<i<<"\n";
return 200;
}
int main()
{
//Return type is an std::any..
auto rn = call<std::any>(func, 10);
std::cout<<std::any_cast<int>(rn)<<"\n";
//Return type is void and cannot be converted to std::any..
//call<void>(func, 10); //Error here because void type is not `std::any` type..
//Return type of `func3` is an integer.. `call` implicitly constructs an std::any from that..
auto res = call<std::any>(func3, 20);
std::cout<<std::any_cast<int>(res)<<"\n";
return 0;
}
请注意,密钥是他们的UserID,我不希望将用户可能选择错误部门或错误建筑物的情况列入白名单。这就是它必须匹配两个值的原因。
答案 0 :(得分:3)
当我看到重复时,我通常会尝试将代码拉出到辅助函数中。
我看到这种模式重复了几次:
case BUILDING:
history = new KeyValuePair<string, Enum>(Model.UserID, (DEPARTMENTSETTINGS.Departments)Model.DepartmentSelectedIndex);
if (!WhiteList.Contains(history))
{
WhiteList.Add(history.Key, history.Value);
await power.InvokeAsync();
}
break;
每次只有两个位改变(BUILDING和 DEPARTMENTSETTINGS)。所以,让我们把它拉到自己的辅助函数中:
private async Task CheckWhiteList(PowerShell power)
{
switch ((Building)Model.BuildingSelectedIndex)
{
case Building.CaneRidge:
await InvokeScriptIfNotYetWhiteListedAsync(power, Model.UserID, (CaneRidgeSettings.Departments)Model.DepartmentSelectedIndex);
break;
case Building.Carothers:
await InvokeScriptIfNotYetWhiteListedAsync(power, Model.UserID, (CarothersSettings.Departments)Model.DepartmentSelectedIndex);
break;
case Building.CSC:
await InvokeScriptIfNotYetWhiteListedAsync(power, Model.UserID, (CSCSettings.Departments)Model.DepartmentSelectedIndex);
break;
case Building.HQ:
await InvokeScriptIfNotYetWhiteListedAsync(power, Model.UserID, (HQSettings.Departments)Model.DepartmentSelectedIndex);
break;
default:
break;
}
}
private async Task InvokeScriptIfNotYetWhiteListedAsync(PowerShell power, string userID, Enum department)
{
var history = new KeyValuePair<string, Enum>(userID, department);
if (!WhiteList.Contains(userID))
{
WhiteList.Add(history.Key, history.Value)
await power.InvokeAsync()
}
}
但仍有重复的代码。如果我们将InvokeScriptIfNotYetWhiteListedAsync()
的电话拨出交换机怎么办?
我还在辅助函数中看到,我们正在为KeyValuePair
的调用创建.Contains()
。我们可以使用.ContainsKey()
来避免创建KeyValuePair
对象。
private async Task CheckWhiteList(PowerShell power)
{
Enum department;
switch ((Building)Model.BuildingSelectedIndex)
{
case Building.CaneRidge:
department = (CaneRidgeSettings.Departments)Model.DepartmentSelectedIndex;
break;
case Building.Carothers:
department = (CarothersSettings.Departments)Model.DepartmentSelectedIndex;
break;
case Building.CSC:
department = (CSCSettings.Departments)Model.DepartmentSelectedIndex;
break;
case Building.HQ:
department = (HQSettings.Departments)Model.DepartmentSelectedIndex;
break;
default:
return;
}
await InvokeScriptIfNotYetWhiteListedAsync(power, Model.UserID, department);
}
private async Task InvokeScriptIfNotYetWhiteListedAsync(PowerShell power, string userID, Enum department)
{
// I find compound conditionals sometimes are easier to read if they're
// given a name before being used.
var alreadyWhiteListed = WhiteList.ContainsKey(userID) && WhiteList[userID] == department;
if (!alreadyWhiteListed)
{
WhiteList.Add(userID, department)
await power.InvokeAsync()
}
}
既然switch语句只是选择了正确的Enum值,我们也可以把它拉出来帮助它并给它一个好名字:
private async Task CheckWhiteList(PowerShell power)
{
Enum department = GetDepartmentEnumForBuilding((Building)Model.BuildingSelectedIndex);
await InvokeScriptIfNotYetWhiteListedAsync(power, Model.UserID, department);
}
private Enum GetDepartmentEnumForBuilding(Building building)
{
switch (building)
{
case Building.CaneRidge:
return (CaneRidgeSettings.Departments)Model.DepartmentSelectedIndex;
case Building.Carothers:
return (CarothersSettings.Departments)Model.DepartmentSelectedIndex;
case Building.CSC:
return (CSCSettings.Departments)Model.DepartmentSelectedIndex;
case Building.HQ:
return (HQSettings.Departments)Model.DepartmentSelectedIndex;
default:
throw new ArgumentOutOfRangeException(nameof(building));
}
}
private async Task InvokeScriptIfNotYetWhiteListedAsync(PowerShell power, string userID, Enum department)
{
var alreadyWhiteListed = WhiteList.ContainsKey(userID) && WhiteList[userID] == department;
if (!alreadyWhiteListed)
{
WhiteList.Add(userID, department)
await power.InvokeAsync()
}
}
现在似乎没有太多重复的代码,并且每个函数的工作量都较少,因此它们可能更容易理解。
如果我们不想使用Enum
,我们可以做其他重构,但这可能已经足够好了。
答案 1 :(得分:1)
放手一搏:
public static Dictionary<Building, Func<int, Enum>> mySwitch = new Dictionary<Building, Func<int, Enum>>()
{
{ Building.CaneRidge, n => (CaneRidgeSettings.Departments)n },
{ Building.Carothers, n => (CarothersSettings.Departments)n },
{ Building.CSC, n => (CSCSettings.Departments)n },
{ Building.HQ, n => (HQSettings.Departments)n },
};
private async Task CheckWhiteList(PowerShell power)
{
var history = new KeyValuePair<string, Enum>(Model.UserID, mySwitch[(Building)Model.BuildingSelectedIndex](Model.DepartmentSelectedIndex));
if (!WhiteList.Contains(history))
{
WhiteList.Add(history.Key, history.Value);
await power.InvokeAsync();
}
}
如果它对您有用,请告诉我,我可以解释一下。我现在必须跑。