J'utilise des propriétés auto-implémentées. Je pense que le moyen le plus rapide de corriger ce qui suit est de déclarer ma propre variable de support.
public Point Origin { get; set; }
Origin.X = 10; // fails with CS1612
Message d'erreur: Impossible de modifier la valeur de retour de 'expression' car ce n'est pas une variable
Une tentative de modification d'un type de valeur résultant d'une expression intermédiaire a été effectuée. Parce que la valeur n'est pas conservée, la valeur sera inchangée.
Pour résoudre cette erreur, stockez le résultat de l'expression dans une valeur intermédiaire ou utilisez un type de référence pour l'expression intermédiaire.
En effet, Point
est un type de valeur (struct
).
De ce fait, lorsque vous accédez à la propriété Origin
, vous accédez à un copy de la valeur détenue par la classe, pas à la valeur elle-même comme vous le feriez avec un type de référence (class
), donc si vous définissez la propriété X
dessus, vous définissez la propriété sur la copie, puis vous la supprimez, en laissant la valeur originale inchangée. Ce n'est probablement pas ce que vous vouliez, c'est pourquoi le compilateur vous en avertit.
Si vous souhaitez modifier uniquement la valeur X
, vous devez procéder de la manière suivante:
Origin = new Point(10, Origin.Y);
L'utilisation d'une variable de sauvegarde ne vous aidera pas. Le type Point
est un type de valeur.
Vous devez affecter la valeur Point entière à la propriété Origin: -
Origin = new Point(10, Origin.Y);
Le problème est que lorsque vous accédez à la propriété Origin, ce qui est retourné par get
est une copie de la structure de points dans le champ créé automatiquement par les propriétés Origin. Par conséquent, votre modification du champ X cette copie n’affectera pas le champ sous-jacent. Le compilateur le détecte et vous renvoie une erreur car cette opération est totalement inutile.
Même si vous utilisiez votre propre variable de sauvegarde, votre get
ressemblerait à ceci: -
get { return myOrigin; }
Vous renverriez toujours une copie de la structure en points et vous obtiendrez la même erreur.
Hmm ... après avoir lu votre question plus attentivement, vous voulez peut-être modifier la variable de sauvegarde directement à partir de votre classe: -
myOrigin.X = 10;
Oui, ce serait ce dont vous auriez besoin.
A présent, vous savez déjà quelle est la source de l'erreur. Si un constructeur n'existe pas avec une surcharge pour prendre votre propriété (dans ce cas, X
), vous pouvez utiliser l'initialiseur d'objet (qui fera toute la magie dans les coulisses). Non pas que vous n'ayez pas besoin de rendre vos structures immuables , mais juste en donnant des informations supplémentaires:
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin { get; set; }
}
MyClass c = new MyClass();
c.Origin.X = 23; //fails.
//but you could do:
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor
//instead of
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this.
C'est possible parce que cela se passe dans les coulisses:
Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;
Cela ressemble à une chose très étrange à faire, pas du tout recommandé. Juste en énumérant une autre manière. La meilleure façon de faire est de rendre la structure immuable et de fournir un constructeur approprié.
Je suppose que le problème ici est que vous essayez d'attribuer les sous-valeurs de l'objet dans l'instruction plutôt que d'attribuer l'objet lui-même. Dans ce cas, vous devez affecter l'intégralité de l'objet Point dans la mesure où le type de propriété est Point.
Point newOrigin = new Point(10, 10);
Origin = newOrigin;
J'espère que j'avais un sens là-bas
Le problème est que vous pointez sur une valeur située sur la pile et que la valeur ne sera pas réinfectée dans la propriété orignal. C # ne vous permet donc pas de renvoyer une référence à un type de valeur. Je pense que vous pouvez résoudre ce problème en supprimant la propriété Origin et en utilisant un dépôt public, mais je sais que ce n’est pas une solution intéressante. L'autre solution consiste à ne pas utiliser le point, mais à créer votre propre type de point en tant qu'objet.
En plus de débattre des avantages et des inconvénients des structures par rapport aux classes, j'ai tendance à regarder l'objectif et à aborder le problème sous cet angle.
Cela dit, si vous n'avez pas besoin d'écrire du code derrière la propriété get et set méthodes (comme dans votre exemple), ne serait-il pas plus simple de déclarer simplement la Origin
comme champ de la classe plutôt que comme une propriété? Je pense que cela vous permettrait d’atteindre votre objectif.
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin;
}
MyClass c = new MyClass();
c.Origin.X = 23; // No error. Sets X just fine