Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中避免NullReferenceException的优雅方法#_C#_.net_Syntax_Web - Fatal编程技术网

C# 在C中避免NullReferenceException的优雅方法#

C# 在C中避免NullReferenceException的优雅方法#,c#,.net,syntax,web,C#,.net,Syntax,Web,我想这样做 var path = HttpContext.Current.Request.ApplicationPath; 如果沿途的任何属性为null,则我希望path为null,或者最好为“” 有没有一种优雅的方法可以做到这一点 理想情况下,我喜欢这种行为(没有可怕的表现和丑陋) 字符串路径 try { path = HttpContext.Current.Request.ApplicationPath; } catch { path = null; } 谢谢最短、最有效

我想这样做

var path = HttpContext.Current.Request.ApplicationPath;
如果沿途的任何属性为null,则我希望path为null,或者最好为“”

有没有一种优雅的方法可以做到这一点

理想情况下,我喜欢这种行为(没有可怕的表现和丑陋) 字符串路径

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

谢谢

最短、最有效的路径是对每个级别执行空检查。为了重用,您可以将代码包装成一个助手函数或一个扩展方法。这将使您可以通过该函数安全地访问它,但仍会始终执行空检查

例如:

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;
  }
}
[编辑] C#6不久前发布,它附带了null传播运算符
?。
,这将简化您的案例:

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); 
            }       
    }
公共静态类扩展
{
//安全零检查。
公共静态TOut IfNotNull(此TIn v,函数f)
在哪里上课
兜售者:阶级
{ 
如果(v==null)返回null;
返回f(v);
}       
}
更新(2014年11月)

C#6包含一个名为的东西,这意味着它有语言支持。您的示例可以用C#6编写如下:

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


你可以这样写:

string value = NullHelpers.GetValueOrNull(
    () => HttpContext.Current.Request.ApplicationPath);
public static T GetValueOrNull<T>(Func<T> valueProvider) 
    where T : class
{
    try
    {
        return valueProvider();
    }
    catch (NullReferenceException)
    {
        return null;
    }
}
实现此
NullHelpers.GetValueOrNull
的最简单方法可能如下所示:

string value = NullHelpers.GetValueOrNull(
    () => HttpContext.Current.Request.ApplicationPath);
public static T GetValueOrNull<T>(Func<T> valueProvider) 
    where T : class
{
    try
    {
        return valueProvider();
    }
    catch (NullReferenceException)
    {
        return null;
    }
}
public static T GetValueOrNull(Func valueProvider)
T:在哪里上课
{
尝试
{
返回值提供程序();
}
捕获(NullReferenceException)
{
返回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()();
}
public static T GetValueOrNull(
表达式值(提供程序)
T:在哪里上课
{
变量表达式=(MemberExpression)
((MemberExpression)valueProvider.Body);
var members=新列表();
while(表达式!=null)
{
成员。添加(表达);
表达式=
(MemberExpression)expression.expression;
}
成员。反向();
foreach(成员中的var成员)
{
var func=Expression.Lambda(member.Compile();
如果(func()==null)
{
返回null;
}
}
返回valueProvider.Compile();
}
这也是最慢的方法,因为每个调用将执行一个或多个JIT编译器调用,但是


天气仍然凉爽;-)

2012年5月,当你问这个问题时,我没有看到比“尝试”更简单的解决方案。。。抓住你提供的。唯一的选择是使用“if”或“?”检查每个部分是否为null,这看起来更难看(但可能快一点)

要么你必须写:

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

两者都在毫无例外地进行处理。请注意,如果发现任何空值,两者都使用“快捷方式”中止检查


更新(2017年12月): 由于C#Version 6及更高版本,有一个更好的解决方案可用,即所谓的
Elvis
-运算符(也称为空合并运算符
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;
它的作用完全相同,而且远不止“只是”语法上的糖。与附加的
结合使用??值
您可以轻松地用其他值替换
null
,例如

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

如果无法获得非空值,这将使
路径
变量为空。

我误读并删除了注释是否有合理的方法覆盖运算符来实现此目的?@AK_uu;Nope,您不能只定义您自己的运算符,并覆盖。。。在这种情况下,这将是令人不快的:).NET团队知道对此类功能的“请求”,但可能不会在C#5-->中发布,并且(继续,呸,编辑超时)我看不到作为运算符重写此功能的方法,因为它接受lambda表达式-我不知道这是否可能,但即使是,那会很难看:)。此外,为任意类型重载现有运算符(如果可能的话)将为冲突和意外WTF显示一个全新的字段。很好的解决方案!爱死它了!将扩展方法也添加到我们的框架库中;这意味着任何时候你想要得到的值,它只是一个单一的方法调用。这比在许多位置一致地执行相同的空检查要好,而且更简单。。。。你不应该从表达式的底部开始吗?@aku:这就是
members.Reverse()用于:-)。自己测试一下。