web-dev-qa-db-ja.com

C#6.0Null伝播演算子とプロパティの割り当て

この質問は、説明を徹底するために完全に見直されました。

Null伝播されたオブジェクトに対してproperty settersを呼び出すことができないという点で、C#6.0のnull伝播演算子の制限が非常に悪いように見えることに気づきました(ただし、propertyを呼び出すことはできますgetters nullが伝播されたオブジェクトに対して)。生成されたIL(C#に反映しました)からわかるように、null伝播を使用してプロパティセッターを呼び出す機能を制限するものは何もありません。 。

まず、JavaスタイルのGet/Setメソッドと、パブリックゲッター/セッターアクセスを持つプロパティの両方を備えた単純なクラスを作成しました。

_public class Person
{
    public Person(string name, DateTime birthday)
    {
        Name = name;
    }

    public string Name { get; set; }

    public void SetName(string name)
    {
        Name = name;
    }

    public string GetName()
    {
        return Name;
    }
}
_

次のテストクラスでヌル伝播の機能をテストしました。

_public class Program
{
    public static void Main(string[] args)
    {
        Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));

        // This line doesn't work - see documented error below
        person?.Name = "John Smith";

        person?.SetName("John Smith");

        string name = person?.Name;
    }
}
_

割り当ての左側は、変数、プロパティ、またはインデクサーである必要があります。

ただし、これから、SetName(...)を呼び出すことによるJava名前の設定方法が機能し、null伝播プロパティの値の取得も機能することに気付くかもしれません。 。

このコードから生成されたC#を見てみましょう。

_public static void Main(string[] args)
{
    Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));
    if (person != null)
    {
        person.SetName("John Smith");
    }
    string arg_33_0 = (person != null) ? person.Name : null;
}
_

SetNameメソッドに対して使用すると、null伝播は単純なifステートメントに変換され、Nameプロパティゲッターに対して使用すると、三項演算子が次のいずれかに使用されることに注意してください。 Nameまたはnullの値を取得します。

ここで気付いたのは、ifステートメントを使用する場合と三項演算子を使用する場合の動作の違いです。セッターを使用する場合は、ifステートメントを使用すると機能しますが、三項演算子を使用すると機能しません。 t。

_public static void Main(string[] args)
{
    Person person = null;

    if (person != null)
    {
        person.Name = "John Smith";
    }

    person.Name = (person != null) ? "John Smith" : null;
}
_

この例では、ifステートメントと三項演算子の両方を使用して、nullプロパティに割り当てる前に人がNameであるかどうかを確認しています。 ifステートメントは期待どおりに機能します。予想どおり、三項演算子を使用したステートメントは失敗します

オブジェクト参照がオブジェクトインスタンスに設定されていません。

私の意見では、制限は、null伝播をifステートメントまたは3項式のいずれかに変換するC#6.0の機能に起因します。 ifステートメントのみを使用するように設計されている場合、プロパティの割り当てはnull伝播を介して機能します。

これまでのところ、なぜこれが不可能であるのかについての説得力のある議論を見たことがないので、私はまだ答えを探しています!

27
Matthew Layton

あなただけではありません! SLaks これを 問題 (現在 ここ )として提起しました

なぜこのようなコードを書くことができないのですか?

Process.GetProcessById(2)?.Exited += delegate { };

そしてそれが「設計による」として一時的に閉じられた後

?。演算子が左辺値を生成することはないため、これは仕様によるものです。

誰かが、イベントハンドラーだけでなくプロパティセッターにも良いだろうとコメントしました

たぶん、次のようなプロパティセッターもリクエストに追加します。

Object?.Prop = false;

そしてそれはC#7の機能リクエストとして再開されました。

25
Rawling

このようにnull伝搬演算子を使用することはできません。

この演算子を使用すると、式の評価中にnullを伝播できます。エラーが示すように、割り当てのターゲットとして使用することはできません。

あなたは昔ながらのヌルチェックに固執する必要があります:

if (a != null)
{
    a.Value = someValue;
}
4
i3arnon