函数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"。但那不是个好主意,不是吗?