Just wondering what is the best practice when using functions or properties. I have a class
Class Person
Property FirstName as String
Property LastName as String
'code to use
Return $"{LastName.ToUpper}, {FirstName}"
End Class
What's the best way?
- ReadOnly Property FullName as String
- Function FullName as String
- Shared Function FullName(p as Person) as String
My understanding is 3 would be better as 1 or 2 would be part of the object, but there is nothing unique in what they do to an object, so the same code would be duplicated for every Person object.
CodePudding user response:
At the time of writing this answer, there is a vote to close your question on the basis that it is "likely to be answered with opinions rather than facts and citations". About your 3.
this is surely not the case because a shared member alone can only access shared members directly so it is out of the question. As for 1.
and 2.
, this is what they would look like:
Class Person
Public Property FirstName as String
Public Property LastName as String
Public Function GetFullName() As String
Return $"{LastName.ToUpper}, {FirstName}"
End Function
Public ReadOnly Property FullName As String
Public Get
Return $"{LastName.ToUpper}, {FirstName}"
End
End Property
End Class
Calling them:
Dim p As New Person() With {.FirstName = "John", .LastName = "Doe"}
Console.WriteLine(p.GetFullName())
Console.WriteLine(p.FullName)
DOE, John
DOE, John
Both do the same thing. Here comes the opinion part:
I prefer the property in this case because it doesn't do much work. I expect a method to do a little more work behind the scenes - I wouldn't expect a property to take much time to run, but am ok with a method delaying a bit - but that's a bit subjective. From this answer, "Methods imply doing so action, while properties imply getting some data." with which I agree (also with some other good info in the Q&A).
A way to pigeonhole a shared function into this answer would be to write a function which can be used by the instance members, but it can't access the name properties directly. As for the public API, the question is still between 1.
and 2.
. It may look something like this
Class Person
Public Property FirstName As String
Public Property LastName As String
Public Function GetFullName() As String
Return getFullName(FirstName, LastName)
End Function
Public ReadOnly Property FullName As String
Get
Return getFullName(FirstName, LastName)
End Get
End Property
Private Shared Function getFullName(firstName As String, lastName As String)
Return $"{lastName.ToUpper}, {firstName}"
End Function
Private Shared Function getFullName(p As Person)
Return $"{p.LastName.ToUpper}, {p.FirstName}"
End Function
End Class
CodePudding user response:
My understanding is 3 would be better as 1 or 2 would be part of the object, but there is nothing unique in what they do to an object, so the same code would be duplicated for every Person object.
No, code is not duplicated. All object instances of a class contain their own copy of their fields, but there is only one copy of the code in memory.
An instance method can be considered syntactic sugar for a shared method which takes the object instance as its first parameter, so there is no difference between 2 and 3 with respect to memory usage. Option 2 has a few advantages over option 3, though:
- It's more idiomatic:
myPerson.GetFullName()
is easier to read thanPerson.GetFullName(myPerson)
. - It allows you to add polymorphism, if needed: An instance method can be overridden in a subclass, and instance methods can be used to implement interfaces.
A read-only property can be considered syntactic sugar for an instance method, so there's not much difference between 1 and 2 either. Microsoft published a guideline to choose between those two:
In particular, it advises to choose a property if "the member represents a logical attribute of the type", which is the case here. It also lists a number of criteria for choosing a method (expensive operation, conversion, different result on subsequent calls, side effects, state copy), none of which apply here. Thus, I'd say that option 1 is a clear winner here.