ByRef vs ByVal Précisions
Je viens juste de commencer sur une classe permettant de gérer les connexions client à un serveur TCP. Voici le code que j'ai écrit jusqu'à présent:
Imports System.Net.Sockets
Imports System.Net
Public Class Client
Private _Socket As Socket
Public Property Socket As Socket
Get
Return _Socket
End Get
Set(ByVal value As Socket)
_Socket = value
End Set
End Property
Public Enum State
RequestHeader ''#Waiting for, or in the process of receiving, the request header
ResponseHeader ''#Sending the response header
Stream ''#Setup is complete, sending regular stream
End Enum
Public Sub New()
End Sub
Public Sub New(ByRef Socket As Socket)
Me._Socket = Socket
End Sub
End Class
Donc, sur mon constructeur surchargé, je suis acceptant un référence à un instance d'un System.Net.Sockets.Socket
, oui?
Maintenant, sur mon Socket
des biens, lors de la définition de la valeur, il est nécessaire d'être ByVal
. C'est ma compréhension que la instance dans la mémoire est copié, et ce nouvelle instance est passé à value
, et mon code définit _Socket
pour faire référence à cette instance en mémoire. Oui?
Si cela est vrai, alors je ne vois pas pourquoi je veux utiliser les propriétés pour rien, mais en natif types. J'imagine que il peut y avoir un gain de performance si la copie des instances de classe avec beaucoup de membres. Aussi, pour que ce code en particulier, j'imagine un copié socket instance ne serait pas vraiment travailler, mais je n'ai pas encore testé.
De toute façon, si vous pouviez confirmer ma compréhension, ou d'expliquer les failles dans mon brouillard logique, je vous en serais très reconnaissante.
OriginalL'auteur Brad | 2010-12-08
Vous devez vous connecter pour publier un commentaire.
Je pense que vous êtes la confusion entre le concept de références vs les types valeur et
ByVal
vsByRef
. Même si leurs noms sont un peu trompeuses, ils sont orthogonaux questions.ByVal
dans VB.NET signifie qu'une copie de la valeur fournie sera envoyé à la fonction. Pour les types de valeur (Integer
,Single
, etc.) cela fournira une copie de la valeur. Avec les grands types, ce qui peut être très inefficace. Pour les types de référence (String
, des instances de classe) une copie de la référence est passée. Car une copie est transmise à des mutations au paramètre via=
il ne sera pas visible à l'appel de la fonction.ByRef
dans VB.NET signifie qu'une référence à la valeur d'origine sera envoyé à la fonction (1). C'est presque comme si la valeur d'origine est directement utilisé dans la fonction. Des opérations comme=
affectera la valeur d'origine et être immédiatement visibles dans la fonction appelante.Socket
est un type de référence (lire en classe) et donc de la passer avecByVal
est bon marché. Même si elle effectue une copie c'est une copie de la référence, pas une copie de l'instance.(1) Ce n'est pas vrai à 100%, mais parce que VB.NET prend en charge plusieurs types de ByRef à la callsite. Pour plus de détails, voir le billet de blog Le nombre de cas de ByRef
+1 - 'je pense que vous êtes la confusion entre le concept de références vs les types valeur et ByVal vs ByRef. Même si les noms sont un peu trompeuses ils sont orthogonaux.", à venir à partir de C++ ceci m'a jeté.
un excellent & réponse détaillée
Je ne jamais passer les types de référence ByRef quand je suis de passage d'une référence null à une procédure dans laquelle j'instancie une nouvelle instance de l'objet que je veux passer de nouveau à la procédure d'appel. Vous pouvez obtenir la même chose par l'instanciation d'une nouvelle instance de l'objet en premier et ensuite le passant à la même procédure mais cette fois, ByVal.
OriginalL'auteur JaredPar
Rappelez-vous que
ByVal
encore transmet les références. La différence est que vous obtenez une copie de la référence.Oui, mais il en serait de même si vous l'avez demandé
ByVal
à la place. La différence est que, avecByVal
vous obtenez une copie de la référence — vous avez une nouvelle variable. AvecByRef
, c'est la même variable.Nope. Seule la référence est copiée. Par conséquent, vous êtes toujours de travailler avec le même instance.
Voici un exemple de code qui l'explique plus clairement:
Baz.Bar = "replaced"
, et votre MyFoo variable est nuked à la fois avec le ByVal et ByRef version. Un bug qui a mordu plusieurs un développeur VB. Si votre Barre de propriété avait seulement un getter, alors il serait devenu immuable et vous serait en sécurité. Buste comme il est, le code est cassé.Je comprends la différence venait de initialisé MyFoo mal. Devrait être plus clair maintenant.
OriginalL'auteur Joel Coehoorn
Ma compréhension a toujours été que le ByVal/ByRef décision est réellement le plus important pour les types de valeur (sur la pile). ByVal/ByRef fait très peu de différence pour les types de référence (sur le tas), à MOINS que ce type de référence est immuable comme Système.Chaîne de caractères. Pour les objets mutables, il n'a pas d'importance si vous transmettez un objet ByRef ou ByVal, si vous le modifiez dans la méthode de l'appel de la fonction voir les modifications.
Socket est mutable, de sorte que vous pouvez passer n'importe quelle manière que vous voulez, mais si vous ne voulez pas conserver les modifications à l'objet que vous avez besoin de faire une copie de vous-même.
HttpClient
ByRef en pensant que je pouvais changer les en-tête d'Autorisation seulement. Nope; il modifie la procédure d'appel de l'en-tête d'Authentification. Assez ennuyeux trop que je me serais attendu que l'une des raisons pour ByVal (contrairement à ByRef) est de sorte que vous pouvez obliviously faire ce que vous aimez à la copie.OriginalL'auteur mattmc3
Pense de C, et la différence entre un scalaire, comme int, et un pointeur de int et un pointeur vers un pointeur de int.
Passant un est par valeur.
En passant a1 est une référence à un; c'est l'adresse d'un.
En passant a2 est une référence à un état de référence; ce qui est passé est l'adresse de a1.
Passage d'une Liste de variables à l'aide de ByRef est analogue pour le scénario a2. Il est déjà une référence. Vous êtes de passage à une référence à une référence. Faire cela signifie que vous pouvez non seulement modifier le contenu de la Liste, vous pouvez modifier le paramètre de point à un autre de la Liste. Cela signifie également que vous ne pouvez pas passer un littéral null à la place d'une instance de Liste
OriginalL'auteur ChrisG65