web-dev-qa-db-fra.com

Utilisation de l'opérateur null-conditionnel sur le côté gauche d'une affectation

J'ai quelques pages, chacune avec une propriété nommée Data. Sur une autre page, je configure ces données comme ceci:

if (MyPage1 != null)
    MyPage1.Data = this.data;
if (MyPage2 != null)
    MyPage2.Data = this.data;
if (MyPage3 != null)
    MyPage3.Data = this.data;

Existe-t-il une possibilité d'utiliser l'opérateur à condition nulle sur MyPage? Je pense à quelque chose comme ça:

MyPage?.Data = this.data;

Mais quand je l'écris comme ceci, j'obtiens l'erreur suivante:

Le côté gauche d'une affectation doit être une variable, une propriété ou un indexeur.

Je sais que c'est parce que MyPage pourrait être nul et que le côté gauche ne serait plus une variable.

Ce n'est pas que je ne peux pas l'utiliser comme je l'ai déjà mais je veux juste savoir s'il y a une possibilité d'utiliser l'opérateur null-conditionnel à ce sujet.

29
diiN__________

L'opérateur de propagation nul renvoie une valeur. Et comme vous devez avoir une variable sur le côté gauche d'une affectation, et non une valeur, vous ne pouvez pas l'utiliser de cette façon.

Bien sûr, vous pouvez raccourcir les choses en utilisant l'opérateur tenary, mais cela, en revanche, n'aide pas vraiment l'aspect lisibilité.

Le commentaire de Joachim Isaksson sur votre question montre une approche différente qui devrait fonctionner.

10
Allmighty

Comme l'a suggéré Joachim Isaksson dans les commentaires, j'ai maintenant une méthode SetData(Data data) et je l'utilise comme ceci:

MyPage1?.SetData(this.data);
MyPage2?.SetData(this.data);
MyPage3?.SetData(this.data);
7
diiN__________

Je suis venu avec l'extension suivante,

public static class ObjectExtensions
{
    public static void SetValue<TValue>(this object @object, string propertyName, TValue value)
    {
        var property = @object.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
        if (property?.CanWrite == true)
            property.SetValue(@object, value, null);
    }
}

Qui peut être appelé globalement; cela ne fonctionne que sur les propriétés publiques.

myObject?.SetValue("MyProperty", new SomeObject());

La version améliorée suivante fonctionne sur n'importe quoi,

public static void SetValue<TObject>(this TObject @object, Action<TObject> assignment)
{
    assignment(@object);
}

Et peut aussi être appelé globalement,

myObject?.SetValue(i => i.MyProperty = new SomeObject());

Mais le nom de l'extension est quelque peu trompeur car le Action ne nécessite pas exclusivement une affectation.

2
James M

Assez tard pour la fête, mais je suis arrivé à cet article avec un problème similaire. J'ai pris l'idée de la méthode SetValue et créé une méthode d'extension générique, comme ci-dessous:

/// <summary>
/// Similar to save navigation operator, but for assignment. Useful for += and -= event handlers. 
/// If <paramref name="obj"/> is null, then <paramref name="action"/> is not performed and false is returned.
/// If <paramref name="obj"/> is not null, then <paramref name="action"/> is performed and true is returned.
/// </summary>
public static bool SafeAssign<T>(this T obj , Action<T> action ) where T : class 
{
  if (obj is null) return false;
  action.Invoke(obj);
  return true;
}

Exemple d'utilisation, pour attacher et détacher un événement d'un gestionnaire:

public void Attach() => _control.SafeAssign(c => c.MouseDown += Drag);

public void Detach() => _control.SafeAssign(c => c.MouseDown-= Drag);

J'espère que quelqu'un le trouvera utile :)

1
Paul Williams

Essayez ceci Ajoutez toutes vos pages à myPageList.

IEnumerable<MyPage> myPageList;

foreach(MyPage myPage in myPageList)
{
if (myPage != null)
    myPage.Data = this.data;
}

Une méthode d'extension SetValue générique (mais uniquement pour les propriétés ref) serait:

    public static void SetValue<T>(this T property, T value)
    {
        property = value;
    }

Et sera utilisé comme

ButtonOrNull?.Visibility.SetValue(Visibility.Hidden);
0
copa017