7

やりたい

var path = HttpContext.Current.Request.ApplicationPath;

途中のプロパティのいずれかがnullの場合、パスをnullにするか、「」の方が良いでしょう。

Ternariesなしでこれを行うエレガントな方法はありますか?

理想的には、この動作が必要です (恐ろしいパフォーマンスと醜さなしで) 文字列パス;

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 の安全な逆参照 operator を探していると思いますが?.、あなたが最初ではありません。 リンクされたトピックから、私が個人的に最も気に入っている解決策はこれです(これかなり良さそうです)。次に、次のことができます。

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

関数名はいつでも少し短くすることができます。これは、式内のオブジェクトのいずれかが null の場合は null を返し、それ以外の場合は ApplicationPath を返します。値型の場合、最後に null チェックを 1 回実行する必要があります。とにかく、すべてのレベルで 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()();
}

これは、各呼び出しが 1 つまたは複数の JIT コンパイラーの呼び出しを行うため、物事を行う最も遅い方法でもありますが...

それはまだクールです;-)

于 2012-05-30T12:15:04.610 に答える
2

2012 年 5 月にあなたが質問したとき、私はあなたが提供した try ... catch よりも簡単な解決策を見つけられませんでした。唯一の代替手段 - 「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;

また:

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

どちらも例外処理なしで実行しています。どちらも「ショートカット」を使用して、null 値が見つかった場合にチェックを中止していることに注意してください。


更新 (2017 年 12 月): C# バージョン 6 以降、いわゆるElvis-Operator (null 合体演算子?.とも呼ばれ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;

これはまったく同じことを行い、「単なる」構文糖よりもはるかに多くのIMHOです。appended と組み合わせると、他の値に?? value簡単に置き換えることができます。null

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

これにより、pathnull 以外の値を取得できない場合、変数は空になります。

于 2012-05-30T12:35:01.700 に答える
2

最短かつ最もパフォーマンスの高いパスは、すべてのレベルに対して null チェックを実行することです。再利用するために、そのコードをヘルパー関数または拡張メソッドにラップできます。これにより、その関数を介して安全にアクセスできますが、一貫して 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;
  }
}
于 2012-05-30T11:48:44.807 に答える