112

C# で、この例の PropertyC から値を引き出したいとします。ObjectA、PropertyA、および PropertyB はすべて null にすることができます。

ObjectA.PropertyA.PropertyB.PropertyC

最小限のコードで安全に PropertyC を取得するにはどうすればよいですか?

今私はチェックします:

if(ObjectA != null && ObjectA.PropertyA !=null && ObjectA.PropertyA.PropertyB != null)
{
    // safely pull off the value
    int value = objectA.PropertyA.PropertyB.PropertyC;
}

このようなことをもっと行うとよいでしょう (疑似コード)。

int value = ObjectA.PropertyA.PropertyB ? ObjectA.PropertyA.PropertyB : defaultVal;

null合体演算子でさらに折りたたむ可能性があります。

編集もともと、2番目の例はjsのようなものだと言いましたが、jsでは機能しないことが正しく指摘されていたので、疑似コードに変更しました。

4

19 に答える 19

140

C# 6 では、 Null Conditional Operatorを使用できます。したがって、元のテストは次のようになります。

int? value = objectA?.PropertyA?.PropertyB?.PropertyC;
于 2014-11-07T02:03:32.820 に答える
28

短い延長方法:

public static TResult IfNotNull<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
  where TResult : class where TInput : class
{
  if (o == null) return null;
  return evaluator(o);
}

使用する

PropertyC value = ObjectA.IfNotNull(x => x.PropertyA).IfNotNull(x => x.PropertyB).IfNotNull(x => x.PropertyC);

この単純な拡張メソッドと、 http://devtalk.net/csharp/chained-null-checks-and-the-maybe-monad/で見つけることができるその他の多くのメソッド

編集:

しばらく使用した後、このメソッドの適切な名前は、元の With() ではなくIfNotNull()にする必要があると思います。

于 2014-04-02T10:56:53.167 に答える
16

クラスにメソッドを追加できますか? そうでない場合、拡張メソッドの使用について考えたことはありますか? というオブジェクト タイプの拡張メソッドを作成できますGetPropC()

例:

public static class MyExtensions
{
    public static int GetPropC(this MyObjectType obj, int defaltValue)
    {
        if (obj != null && obj.PropertyA != null & obj.PropertyA.PropertyB != null)
            return obj.PropertyA.PropertyB.PropertyC;
        return defaltValue;
    }
}

使用法:

int val = ObjectA.GetPropC(0); // will return PropC value, or 0 (defaltValue)

ちなみに、これは .NET 3 以降を使用していることを前提としています。

于 2010-08-12T13:50:14.563 に答える
12

あなたのやり方は正しいです。

Linq 式を使用して、ここで説明されているようなトリックを使用できます。

int value = ObjectA.NullSafeEval(x => x.PropertyA.PropertyB.PropertyC, 0);

しかし、各プロパティを手動でチェックするのははるかに遅くなります...

于 2010-08-12T13:48:18.943 に答える
11

デメテルの法則を遵守するためのリファクタリング

于 2010-08-12T13:58:09.333 に答える
10

2014 年の更新: C# 6 には、?.「安全なナビゲーション」または「null 伝播」と呼ばれるさまざまな新しい演算子があります。

parent?.child

詳細については、 http://blogs.msdn.com/b/jerrynixon/archive/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator.aspxを参照してください。

これは長い間非常に人気のあるリクエスト でした

于 2014-05-20T15:04:35.207 に答える
8

あなたは明らかにNullable Monadを探しています:

string result = new A().PropertyB.PropertyC.Value;

になる

string result = from a in new A()
                from b in a.PropertyB
                from c in b.PropertyC
                select c.Value;

nullnull 許容プロパティのいずれかが null の場合、これは を返します。それ以外の場合は、 の値Value

class A { public B PropertyB { get; set; } }
class B { public C PropertyC { get; set; } }
class C { public string Value { get; set; } }

LINQ 拡張メソッド:

public static class NullableExtensions
{
    public static TResult SelectMany<TOuter, TInner, TResult>(
        this TOuter source,
        Func<TOuter, TInner> innerSelector,
        Func<TOuter, TInner, TResult> resultSelector)
        where TOuter : class
        where TInner : class
        where TResult : class
    {
        if (source == null) return null;
        TInner inner = innerSelector(source);
        if (inner == null) return null;
        return resultSelector(source, inner);
    }
}
于 2010-08-12T14:03:16.640 に答える
6

タイプの空の値があると仮定すると、1 つのアプローチは次のようになります。

var x = (((objectA ?? A.Empty).PropertyOfB ?? B.Empty).PropertyOfC ?? C.Empty).PropertyOfString;

私は C# の大ファンですが、新しい Java (1.7?) で非常に優れているのは .? オペレーター:

 var x = objectA.?PropertyOfB.?PropertyOfC.?PropertyOfString;
于 2010-08-12T14:01:01.813 に答える
4

このコードは「最小限のコード」ですが、ベスト プラクティスではありません。

try
{
    return ObjectA.PropertyA.PropertyB.PropertyC;
}
catch(NullReferenceException)
{
     return null;
}
于 2010-08-12T13:48:35.930 に答える
3

新しい C# 6.0 で何かを見ました。これは「?」を使用したものです。チェックする代わりに

たとえば、使用する代わりに

if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{ 
  var city = person.contact.address.city;
}

あなたは単に使用します

var city = person?.contact?.address?.city;

誰かの役に立てば幸いです。


アップデート:

あなたは今このようにすることができます

 var city = (Person != null)? 
           ((Person.Contact!=null)? 
              ((Person.Contact.Address!= null)?
                      ((Person.Contact.Address.City!=null)? 
                                 Person.Contact.Address.City : null )
                       :null)
               :null)
            : null;
于 2015-06-28T10:28:36.067 に答える
2

あなたはこれを行うことができます:

class ObjectAType
{
    public int PropertyC
    {
        get
        {
            if (PropertyA == null)
                return 0;
            if (PropertyA.PropertyB == null)
                return 0;
            return PropertyA.PropertyB.PropertyC;
        }
    }
}



if (ObjectA != null)
{
    int value = ObjectA.PropertyC;
    ...
}

または、さらに良いかもしれません:

private static int GetPropertyC(ObjectAType objectA)
{
    if (objectA == null)
        return 0;
    if (objectA.PropertyA == null)
        return 0;
    if (objectA.PropertyA.PropertyB == null)
        return 0;
    return objectA.PropertyA.PropertyB.PropertyC;
}


int value = GetPropertyC(ObjectA);
于 2010-08-12T13:57:12.893 に答える
1

次の拡張機能を使用できます。これは本当に優れていると思います。

/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<TF, TR>(TF t, Func<TF, TR> f)
    where TF : class
{
    return t != null ? f(t) : default(TR);
}

/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<T1, T2, TR>(T1 p1, Func<T1, T2> p2, Func<T2, TR> p3)
    where T1 : class
    where T2 : class
{
    return Get(Get(p1, p2), p3);
}

/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<T1, T2, T3, TR>(T1 p1, Func<T1, T2> p2, Func<T2, T3> p3, Func<T3, TR> p4)
    where T1 : class
    where T2 : class
    where T3 : class
{
    return Get(Get(Get(p1, p2), p3), p4);
}

そして、それは次のように使用されます:

int value = Nulify.Get(objectA, x=>x.PropertyA, x=>x.PropertyB, x=>x.PropertyC);
于 2013-12-10T07:49:36.977 に答える
1

Nullable 型と同様のパターンを使用して、PropertyA の型 (または、型でない場合は拡張メソッド) に独自のメソッドを記述します。

class PropertyAType
{
   public PropertyBType PropertyB {get; set; }

   public PropertyBType GetPropertyBOrDefault()
   {
       return PropertyB != null ? PropertyB : defaultValue;
   }
}
于 2010-08-12T13:47:42.527 に答える
0

それは不可能。null の逆参照が原因で null の
ObjectA.PropertyA.PropertyB場合は失敗します。これはエラーです。ObjectA

if(ObjectA != null && ObjectA.PropertyA... は短絡のために機能します。つまり、 is かどうかはObjectA.PropertyA決してチェックされません。ObjectAnull

あなたが提案する最初の方法は、意図を持った最善かつ最も明確な方法です。それほど多くのヌルに依存することなく、再設計を試みることができれば。

于 2010-08-12T13:48:20.867 に答える
0

この投稿に偶然出くわしました。

???しばらく前に、Visual Studio Connect で新しいオペレーターの追加について提案しました。

http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4104392-add-as-an-recursive-null-reference-check-opera

これには、フレームワーク チームによる作業が必要になりますが、言語を変更する必要はなく、コンパイラ マジックを実行するだけです。アイデアは、コンパイラがこのコードを変更する必要があるというものでした (構文は atm で許可されていません)。

string product_name = Order.OrderDetails[0].Product.Name ??? "no product defined";

このコードに

Func<string> _get_default = () => "no product defined"; 
string product_name = Order == null 
    ? _get_default.Invoke() 
    : Order.OrderDetails[0] == null 
        ? _get_default.Invoke() 
        : Order.OrderDetails[0].Product == null 
            ? _get_default.Invoke() 
            : Order.OrderDetails[0].Product.Name ?? _get_default.Invoke()

nullチェックの場合、これは次のようになります

bool isNull = (Order.OrderDetails[0].Product ??? null) == null;
于 2013-12-09T13:26:58.167 に答える
0

このアプローチは、ラムダ ゴブリー グックを乗り越えれば、かなり簡単です。

public static TProperty GetPropertyOrDefault<TObject, TProperty>(this TObject model, Func<TObject, TProperty> valueFunc)  
                                                        where TObject : class
    {
        try
        {
            return valueFunc.Invoke(model);
        }
        catch (NullReferenceException nex)
        {
            return default(TProperty);
        }
    }

使用法は次のようになります。

ObjectA objectA = null;

Assert.AreEqual(0,objectA.GetPropertyOrDefault(prop=>prop.ObjectB.ObjectB.ObjectC.ID));

Assert.IsNull(objectA.GetPropertyOrDefault(prop => prop.ObjectB));
于 2012-09-21T20:07:17.477 に答える