7

我想做这个

var path = HttpContext.Current.Request.ApplicationPath;

如果沿途的任何属性为空,我希望路径为空,或者“”会更好。

没有三元组有没有一种优雅的方法来做到这一点?

理想情况下,我希望这种行为(没有可怕的性能和丑陋)字符串路径;

try
{
    path = HttpContext.Current.Request.ApplicationPath;
}
catch
{
    path = null;
}

谢谢

4

4 回答 4

11

[编辑]

C# 6 不久前发布了,它附带了 null-propagating operator ?.,这将简化您的案例:

var path = HttpContext?.Current?.Request?.ApplicationPath

由于历史原因,可以在下面找到以前语言版本的答案。


我猜您正在寻找 Groovy 的安全取消引用运算符?.,而您不是第一个。 从链接的主题来看,我个人最喜欢的解决方案是这个那个看起来也很不错)。然后你可以这样做:

var path = HttpContext.IfNotNull(x => x.Current).IfNotNull(x => x.Request).IfNotNull(x => x.ApplicationPath);

您总是可以稍微缩短函数名称。如果表达式中的任何对象为 null,这将返回 null,否则返回 ApplicationPath。对于值类型,您必须在最后执行一次空检查。无论如何,到目前为止没有其他方法,除非您想在每个级别上检查 null。

这是上面使用的扩展方法:

    public static class Extensions
    {
    // safe null-check.
    public static TOut IfNotNull<TIn, TOut>(this TIn v, Func<TIn, TOut> f) 
            where TIn : class  
            where TOut: class 
            { 
                    if (v == null) return null; 
                    return f(v); 
            }       
    }
于 2012-05-30T11:49:27.730 回答
4

更新(2014 年 11 月)

C# 6 包含称为Null Propagation Operator的东西,这意味着对此有语言支持。您的示例可以用 C# 6 编写如下:

var path = HttpContext?.Current?.Request?.ApplicationPath;

如果任何部分包含 null,则完整的表达式将返回 null。


你可以这样写:

string value = NullHelpers.GetValueOrNull(
    () => HttpContext.Current.Request.ApplicationPath);

实现这NullHelpers.GetValueOrNull一点的最简单方法可能是这样的:

public static T GetValueOrNull<T>(Func<T> valueProvider) 
    where T : class
{
    try
    {
        return valueProvider();
    }
    catch (NullReferenceException)
    {
        return null;
    }
}

但到目前为止,解决这个问题的最酷方法是使用表达式树:

public static T GetValueOrNull<T>(
    Expression<Func<T>> valueProvider) 
    where T : class
{
    var expression = (MemberExpression)
        ((MemberExpression)valueProvider.Body).Expression;

    var members = new List<MemberExpression>();

    while (expression != null)
    {
        members.Add(expression);

        expression = 
            (MemberExpression)expression.Expression;
    }

    members.Reverse();

    foreach (var member in members)
    {
        var func = Expression.Lambda<Func<object>>(member).Compile();

        if (func() == null)
        {
            return null;
        }
    }

    return valueProvider.Compile()();
}

这也是最慢的处理方式,因为每次调用都会执行一次或多次 JIT 编译器调用,但是...

它仍然很酷;-)

于 2012-05-30T12:15:04.610 回答
2

最短且性能最高的路径是对每个级别执行空值检查。为了重用,您可以将该代码包装到辅助函数或扩展方法中。这将使您可以通过该功能安全地访问它,但仍会始终执行空检查。

例子:

public void DoSomething()
{
  // Get the path, which may be null, using the extension method
  var contextPath = HttpContext.Current.RequestPath;
}


public static class HttpContextExtensions
{
  public static string RequestPath(this HttpContext context)
  {
    if (context == null || context.Request == null)
    {
      return default(string);
    }

    return context.Request.ApplicationPath;
  }
}
于 2012-05-30T11:48:44.807 回答
2

2012 年 5 月,当您提出问题时,我没有看到比您提供的 try ... catch 更简单的解决方案。唯一的选择 - 使用“if”或“?”检查每个部分是否为空。看起来更丑(但可能更快一点)。

要么你必须写:

path = HttpContext!=null 
    ? (HttpContext.Current!=null 
            ? (HttpContext.Current.Request!=null 
                    ?(HttpContext.Current.Request.ApplicationPath!=null 
                            ? HttpContext.Current.Request.ApplicationPath 
                            : null) 
                    : null) 
            : null) 
    : null;

或者:

if (HttpContext == null || HttpContext.Current == null 
    || HttpContext.Current.Request == null 
    || HttpContext.Current.Request.ApplicationPath  == null)
    path = null;
else
    path = HttpContext.Current.Request.ApplicationPath;

两者都在没有异常处理的情况下这样做。请注意,两者都使用“快捷方式”来中止检查是否找到任何空值。


更新(2017 年 12 月):C# 版本 6 及更高版本开始,您可以使用更好的解决方案,即所谓的Elvis-Operator(也称为空合并运算符?.x?[i]用于数组)。上面的例子

path = HttpContext!=null 
    ? (HttpContext.Current!=null 
            ? (HttpContext.Current.Request!=null 
                    ?(HttpContext.Current.Request.ApplicationPath!=null 
                            ? HttpContext.Current.Request.ApplicationPath 
                            : null) 
                    : null) 
            : null) 
    : null;

这样看起来好多了:

path = HttpContext?.Current?.Request?.ApplicationPath;

这完全一样,恕我直言,不仅仅是“只是”语法糖。结合附加的?? value,您可以轻松地用null其他值替换,例如

path = (HttpContext?.Current?.Request?.ApplicationPath) ?? "";

path如果无法获得非空值,这会使变量为空。

于 2012-05-30T12:35:01.700 回答