2010-09-20 7 views
8

Il y a probablement une explication assez logique à cela, mais j'ai une question.Différence entre la modification d'une variable et d'une propriété

Disons que j'ai une variable de type Rectangle appelée _rect. Je peux maintenant dire _rect.X = 50; sans aucun problème.

Maintenant j'ai une classe avec une propriété appelée Rect qui expose la variable interne _rect.

Alors, si je tente d'écrire Rect.X = 50; j'obtiens l'erreur de compilation suivante:

Impossible de modifier la valeur de retour de « TestClass.Rect » parce qu'il est pas une variable.

Je peux écrire Rect = new Rectangle(50, Rect.Y, Rect.Width, Rect.Height) comme pour un type immuable, mais pour les types non-immuables, y a-t-il un autre moyen de le faire?

Je veux utiliser des propriétés automatiques pour ce champ rectangle, mais c'est vraiment gênant de ne pas pouvoir le modifier dans la classe elle-même.

Y a-t-il un moyen de créer un champ de sauvegarde et de supprimer la propriété auto?

+0

Pouvez-vous nous montrer votre code pour la classe Rect? Et pourquoi n'utilisez-vous pas la classe Rect intégrée? –

+0

Rectangle est-il une classe ou une structure? S'il s'agit d'une structure, essayez d'en faire une classe. – Rohith

+0

Donnez-nous un code complet, il m'est difficile d'imaginer ce que vous dites et cela vous aidera à clarifier votre question. –

Répondre

10

La raison de cette erreur est que Rectangle est un type de valeur (struct) contrairement aux types de référence (classes). Vous ne pouvez pas modifier la propriété X car lorsque vous utilisez le getter de propriété Rect, une nouvelle valeur est renvoyée pour le rectangle (le getter est une fonction). Si c'était un type de référence, vous manipulez le pointeur et ce serait possible.

Ceci est un aspect important de la valeur par rapport aux types de référence à connaître.

+0

Pour être sûr, il n'y a pas de raison * technique * pour laquelle le compilateur n'a pas pu faire ce travail.Le compilateur génère toutes sortes de code supplémentaire pour l'utilisateur (par exemple, la boxe), alors pourquoi pas ici? (En fait, la raison en est probablement qu'elle n'est pas jugée importante puisque les structures doivent être immuables de toute façon.) –

+0

@Konrad - les structures sont copiées lorsqu'elles sont passées, donc l'opération n'aurait tout simplement aucun sens. Ce n'est pas à cause de l'immutabilité (les structures sont mutables). Mais si vous récupérez une copie d'un objet et changez le champ dans cette copie - c'est simplement un NOOP. – viraptor

+0

@viraptor: Je ne suis pas d'accord. L'opération a évidemment du sens: muter une propriété. Le compilateur pourrait facilement faire ce travail en générant du code équivalent à 'var tmp = foo.Property; tmp.x = newX; foo.Property = tmp; '- Le compilateur ** fait ** ceci pour une situation équivalente: Quand vous avez une propriété de type value et que vous écrivez' foo.Property + = 1' cela fonctionne ** ** (testé sur le compilateur Mono). Le compilateur réécrit clairement le code à ce qui précède. –

1

L'accès à la propriété est en réalité un appel de fonction qui renvoie une copie du type de valeur. Rect.X = 50; ne modifierait que cette copie temporaire, pas le champ de sauvegarde lui-même. Lorsque la propriété n'est pas implémentée automatiquement, vous pouvez créer une propriété supplémentaire RectX, qui peut être utilisée pour obtenir et définir la propriété X du rectangle.

+0

Je me sens vraiment stupide maintenant, pour ne pas comprendre pourquoi new Rectangle (...) fonctionnait, et pas Rect.X = 50, puisque les deux auraient travaillé sur la copie, mais quand j'écris un nouveau Rectangle j'appelle l'ensemble au lieu de get. Merci d'avoir clarifié ma tête à ce sujet. Donc, cela signifie fondamentalement non alors. Si je veux ce genre de comportement, je dois utiliser un backing field. –

+0

Lors de l'utilisation d'un champ de sauvegarde, le comportement est toujours le même, le getter et le setter continuent à être des méthodes, donc vous obtiendrez toujours une copie de valeur de l'instance Rectangle. Le comportement que vous souhaitez est uniquement pour les types de référence, car vous obtenez alors la "référence" à l'instance d'objet d'origine. Cependant rectangle est un type de valeur. –

0
class RectangleWithoutFields 
    { 
    // just autoproperties, no fields 

    public int X { get; set; } 

    public int Y { get; set;} 


    public RectangleWithoutFields() 
    { 
     X = 0; 

     Y = 0; 
    } 

    public void ChangeProperties(int x, int y) 

    { 
     X = x; 

     Y = y; 
    } 
} 
+0

Je n'étais pas essayer de créer un nouveau rectangle ici, mais pour le faire fonctionner avec le rectangle standard :) –

Questions connexes