2008-11-20 20 views
1

Disons que vous avez une propriété comme:Que se passe lorsque vous effectuez des tâches à des champs ou des propriétés des propriétés

Person person1; 


public Person Captin{ 
    get{ 
     return person1; 
    } 
    set{ 
     person1 = value; 
    } 
} 

public void SomeFunction(){ 
    Captin.name = "Hook" 
} 

Dans ce cas, si vous définissez le nom sur la propriété, nous savons que le nouveau nom de HOOK être appliqué à la valeur sous-jacente de person1. Et si notre mise en œuvre était un peu différent disons:

public Person Captin{ 
    get{ 
     return ReadCaptinFromDisk(); 
    } 
    set{ 
     WriteCaptinToDisk(value); 
    } 
} 

public void SomeFunction(){ 
    Captin.name = "Hook" 
} 

Dans ce cas, la valeur sous-jacente pour se régler correctement nous devons avoir le code du jeu Captin appelé dans le cadre de la cession à Captin.name.

Je suis curieux de savoir si le code de l'ensemble de paramètres appellera les affectations d'appel de champ ou de méthode sur les références de propriété. en particulier pour ce genre de situation où la valeur doit être propagée sur disque (etc.).

+0

_nous savons que le nouveau nom de Hook sera appliqué à la valeur sous-jacente de person1_ Eh bien, si le type 'Person' est une ** classe **, alors le getter retournera une ** référence ** à la' Personne ** objet **. Cet objet sera alors muté. Le champ privé 'person1' est une autre référence au même objet. Mais si 'Person' était un ** struct ** alors le getter retournerait une ** valeur ** qui serait une ** copie ** de la valeur de' person1'. Par conséquent, même votre premier code ne fonctionnerait pas si 'Person' était un type de valeur. –

Répondre

4

Chaque fois que vous accédez à votre propriété Captin, il lit à partir du disque. Mais si vous changez le nom de la propriété, il n'écrira pas sur le disque. Il n'écrire sur le disque si vous faites quelque chose comme

public void SomeFunction() { 
    Person p = Captin; 
    p.name = "Hook"; 
    Captin = p; 
} 
1

Comme il note @ Joe ne pas écrire sur le disque. Je voulais juste ajouter que c'est parce que vous n'utilisez que le getter, pas le setter. @ L'exemple de Joe utilise les deux. À mon avis, c'est à la fois une très mauvaise utilisation d'un getter et une violation de la séparation des préoccupations. Vous devriez avoir une couche de données qui gère la persistance des données. La logique de ceci ne devrait pas être dans votre objet de gestion.

+0

Je suis surtout intéressé par l'utilisation de copies en cache des objets – minty

1

Le setter de la propriété ne sera appelé que si quelqu'un l'affecte directement. Pour savoir si votre code est correct ou non: c'est une question de documentation.

Chaque fois que vous avez une propriété qui renvoie quelque chose de mutable, vous devez indiquer si ce que les mutations vont faire. Renvoyez-vous une copie de vos "vraies" données, ou s'agit-il des données réelles elles-mêmes? Cela arrive très souvent quand une propriété (ou une méthode normale) renvoie une collection quelconque - elle est mutable? Que se passera-t-il si je le change?

Si vous documentez votre propriété en expliquant que les données retournées sont juste une copie, et que les changements ne seront reflétés nulle part, c'est bon. Si vous le laissez ambigu, c'est quand vous aurez des problèmes.

immutabilité supprime ces préoccupations, bien sûr ...

1

Une variable de type classe, paramètre, le champ, la valeur de retour, ou tout autre lieu de stockage doit être considéré comme tenant un « id objet ». Si un objet Foo a une propriété appelée Bar de type classe qui est sauvegardée par le champ _Bar et _Bar contient "ID d'objet # 24601", l'instruction Foo.Bar.Text = "George" appellera le paramètre Text sur l'objet # 24601 avec la valeur "George" . Notez que cette instruction ne modifiera pas l'objet Foo lui-même (son champ _Bar aura conservé "l'ID d'objet # 24601" avant l'exécution de l'instruction, et le conservera après); cela affectera probablement l'objet # 24601.

Un emplacement de stockage struct-type doit être considéré comme contenant le contenu de tous ses champs (publics et privés).Si Foo.Boz étaient une propriété de type Rectangle (qui est un struct) et sur le terrain de support _Boz, un accès à Foo.Boz créerait une nouvelle instance temporaire de type Rectangle, dont tous les champs seraient copiés de ceux de Foo._Boz. Une tentative de lecture Foo.Boz.X copierait tous les champs de _Boz à une instance temporaire, puis accéder au champ X de cette instance.

Notez que certains compilateurs C# vraiment vieux et mal interpréteraient le code comme Foo.Boz.X = 5; comme Rectangle temp; temp.X = 5;, en rejetant la valeur résultante de temp mais sans émettre d'avertissement. Un tel comportement de compilateur a amené certaines personnes à déclarer que les structures devraient être "immuables" pour s'assurer qu'un tel code va générer une erreur de compilateur plutôt que de produire un comportement bidon. Malheureusement, cette croyance persiste à ce jour malgré le fait que tout compilateur décent interdirait un tel code même si X était un champ mutable.

Notez que la bonne façon idiomatiques de mettre à jour une propriété d'un type struct mutable est:

 
    Rectangle temp = MyListOFRectangles[5]; 
    temp.X = 5; 
    MyListOFRectangles[5] = temp; 

Si Rectangle est connu pour avoir un champ entier public nommé X et MyListOfRectangles est un List<Rectangle>, on n » t besoin de connaître l'une des propriétés, constructeurs, etc. de Rectangle pour savoir que le code ci-dessus changera MyListOfRectangles[5].X mais n'affectera aucune autre propriété de MyListOfRectangles[5], ni aucune propriété de MyListOfRectangles[4]. Nice, clair et facile. Les structures de champ exposé permettent l'édition par morceaux de valeurs d'une manière qui est claire et cohérente, contrairement à tout autre type de type de données.

+0

Upvoted. Donc vous croyez que c'est correct d'écrire des structures mutables (étant donné que le compilateur saura qu'il ne peut pas muter le résultat immédiat d'un appel de méthode, comme dans GetSomeStructValue(). Name = "Hook"; 'qui ne compilera pas? –