函数IIF,如何让它接受2N+1个逻辑表达式的参数?,C#
Function IIF, how to make it take 2N + 1 arguments of logical expressions?, C #
在 Visual Basic 中,有这个 IIF Function,如 Crystal 报告等...
在C#本身中,这个函数是不存在的,但是和这样做是一样的:
bool a = true;
string b = a ? "is_True" : "is_False";
但是为了让代码更容易阅读,我想将它作为 C# 的一个函数来实现,所以它是这样的:
public static T IIf<T>(bool expression, T truePart, T falsePart)
{
return expression ? truePart : falsePart;
}
或者不对真实值进行操作也可以使用委托来完成,访问必要的值:
public static T IIf<T>(bool expression, Func<T> truePart, Func<T> falsePart)
{
return expression ? truePart() : falsePart();
}
到目前为止效果很好...
但是我如何修改这个函数以便我可以接受 2N + 1 个参数?
(N - the number of logical expressions specified)
示例所需结果:
Each odd argument specifies a logical expression;
Each even argument specifies the value that is returned if the previous expression evaluates to true;
The last argument specifies the value that is returned if the previously evaluated logical expressions yielded false.
int value = IIf(Name = "Joel", 1, Name = "Peter", 2, Name = "Maria", 3, 4);
有人可以帮助我吗?
环境:C# - Visual Studio 2017
首先,如评论中所述,这是个坏主意。较新版本的 C# 已经支持 pattern-matching 开关作为语言的 built-in 特性;使用它。
其次,这是一个坏主意,因为 "argument, case1, result1, case2, result2, ..." 的 API 具有难以在 C# 类型系统中表达的签名。
如果我被迫实现这样的 API,我会建议使用元组:
public static R Switch<A, R>(
A item,
R theDefault,
params (A, R)[] cases )
{
foreach(var c in cases)
if (item.Equals(c.Item1))
return c.Item2;
return theDefault;
}
或者,制作一个有用的实用方法并使用它:
public static T FirstOrDefault(
this IEnumerable<T> items,
T theDefault,
Func<T, bool> predicate)
{
foreach(var i in items.Where(predicate))
return i;
return theDefault;
}
public static R Switch<A, R>(
A item,
R theDefault,
params (A, R)[] cases ) =>
cases.FirstOrDefault(
(item, theDefault),
c => item.Equals(c.Item1)).Item2;
如果您因为使用旧版本的 C# 而无法使用元组,您可以创建自己的对类型或使用 key-value 对类型。
但就是不要去那里。如果你需要一个开关,写一个开关。需要字典就写字典。
如果你想保留参数的顺序,如果你努力让函数复制你在别处看到的内容,大概你会这样做,那么你可以这样写:
public T IIf<T>(params object[] objects) {
for(var i = 0; i < objects.Length - 1; i += 2)
if((bool)objects[i])
return (T)objects[i+1];
return (T)objects[objects.Length - 1];
}
但这是一个很好的教训,告诉你为什么要避免这样的事情。首先,您必须明确声明您正在使用的类型。所以你必须像这样使用它:
var value = IIf<int>(Name == "Joel", 1, Name == "Peter", 2, Name == "Maria", 3, 4);
注意将 'int' 作为类型参数传递。您可以通过更改参数的顺序来避免这种情况,以便默认值排在第一位。
但是,如果您只是愿意采用个人模式,嵌套的三元语法可能非常可读:
var value =
Name == "Joel" ? 1
: Name == "Peter" ? 2
: Name == "Maria" ? 3
: 4;
如果您不觉得它可读,那只是因为它需要一些时间来适应。想象一下,从 C# 开发人员转到 VB,然后看到 'IIF'。你会想,"why do they add the extra 'I' in 'IF'?"。我应该创建一个函数 "IF" 来模拟 "IIF"。但那不是个好主意,不是吗?
在 Visual Basic 中,有这个 IIF Function,如 Crystal 报告等...
在C#本身中,这个函数是不存在的,但是和这样做是一样的:
bool a = true;
string b = a ? "is_True" : "is_False";
但是为了让代码更容易阅读,我想将它作为 C# 的一个函数来实现,所以它是这样的:
public static T IIf<T>(bool expression, T truePart, T falsePart)
{
return expression ? truePart : falsePart;
}
或者不对真实值进行操作也可以使用委托来完成,访问必要的值:
public static T IIf<T>(bool expression, Func<T> truePart, Func<T> falsePart)
{
return expression ? truePart() : falsePart();
}
到目前为止效果很好...
但是我如何修改这个函数以便我可以接受 2N + 1 个参数?
(N - the number of logical expressions specified)
示例所需结果:
Each odd argument specifies a logical expression;
Each even argument specifies the value that is returned if the previous expression evaluates to true;
The last argument specifies the value that is returned if the previously evaluated logical expressions yielded false.
int value = IIf(Name = "Joel", 1, Name = "Peter", 2, Name = "Maria", 3, 4);
有人可以帮助我吗?
环境:C# - Visual Studio 2017
首先,如评论中所述,这是个坏主意。较新版本的 C# 已经支持 pattern-matching 开关作为语言的 built-in 特性;使用它。
其次,这是一个坏主意,因为 "argument, case1, result1, case2, result2, ..." 的 API 具有难以在 C# 类型系统中表达的签名。
如果我被迫实现这样的 API,我会建议使用元组:
public static R Switch<A, R>(
A item,
R theDefault,
params (A, R)[] cases )
{
foreach(var c in cases)
if (item.Equals(c.Item1))
return c.Item2;
return theDefault;
}
或者,制作一个有用的实用方法并使用它:
public static T FirstOrDefault(
this IEnumerable<T> items,
T theDefault,
Func<T, bool> predicate)
{
foreach(var i in items.Where(predicate))
return i;
return theDefault;
}
public static R Switch<A, R>(
A item,
R theDefault,
params (A, R)[] cases ) =>
cases.FirstOrDefault(
(item, theDefault),
c => item.Equals(c.Item1)).Item2;
如果您因为使用旧版本的 C# 而无法使用元组,您可以创建自己的对类型或使用 key-value 对类型。
但就是不要去那里。如果你需要一个开关,写一个开关。需要字典就写字典。
如果你想保留参数的顺序,如果你努力让函数复制你在别处看到的内容,大概你会这样做,那么你可以这样写:
public T IIf<T>(params object[] objects) {
for(var i = 0; i < objects.Length - 1; i += 2)
if((bool)objects[i])
return (T)objects[i+1];
return (T)objects[objects.Length - 1];
}
但这是一个很好的教训,告诉你为什么要避免这样的事情。首先,您必须明确声明您正在使用的类型。所以你必须像这样使用它:
var value = IIf<int>(Name == "Joel", 1, Name == "Peter", 2, Name == "Maria", 3, 4);
注意将 'int' 作为类型参数传递。您可以通过更改参数的顺序来避免这种情况,以便默认值排在第一位。
但是,如果您只是愿意采用个人模式,嵌套的三元语法可能非常可读:
var value =
Name == "Joel" ? 1
: Name == "Peter" ? 2
: Name == "Maria" ? 3
: 4;
如果您不觉得它可读,那只是因为它需要一些时间来适应。想象一下,从 C# 开发人员转到 VB,然后看到 'IIF'。你会想,"why do they add the extra 'I' in 'IF'?"。我应该创建一个函数 "IF" 来模拟 "IIF"。但那不是个好主意,不是吗?