Methods and properties in C# - advantages and disadvantages

Asked

Viewed 5,203 times

30

In C# we have properties with getters and setters, which facilitates the insertion and reading of data in an object when some logic should be performed. In other languages, such as Java these tasks are done with methods: when we need logic to read a field or to write to it we use methods getCampo and setCampo, things like.

This approach with methods can also be done in C# and that is where my question lies. What are the advantages and disadvantages in C# of these two approaches? My concern with this question is the following: I’ve been solving object orientation exercises and I noticed that the vast majority of the methods that the exercises ask to encode can become properties in C#. The problem is that it makes the class seem anemic, i.e., having only properties and no logic.

So, are there differences between the two approaches? Is there any kind of recommendation on what technique to use?

EDITION: The @Maniero response is very good and clarifies some things regarding this kind of decision, but I’ll add some examples to illustrate what I’m talking about, just to complete a point. Examples are exercises in Java. One of the exercises I solved called for a class Data with methods getDia, getMes, getAno and isBissexto to decide whether the year is leap. Methods get clearly in C# could be implemented as getters.

It turns out that the isBissexto could also. After all he returns a characteristic of the object rather than performing a behavior. Of course there is a logic to verify this, but I wonder if this would not be a property.

Another exercise asks for a class Prova who must have methods respostaAluno to insert the next question alternative, acertos to return the number of hits, nota to return the note and maior to compare with another proof.

Again, the methods acertos and nota I seem to naturally properties. They are characteristic of proof. There is again a logic to verify this, basically it is necessary to compare each question with the data coming from a template informed in the constructor, but because they seem characteristics I thought they should be properties.

It turns out that by taking these methods and turning these classes into properties, they are almost without functionality, and not only them but many others I’ve seen around. That would indicate the problem I’ve heard is called "anemic model".

Thus, does the decision of something as a property not depend solely on being a feature of the object? Does it also depend on whether or not there is a logic to be used to read or write that data? In cases like the ones I mentioned, it’s more interesting to actually use methods?

  • 2

    In this case, I think anemic means something good... if an anemic class does the same as another "chubby" class. I like the concept of doing more with less, being more expressive with less complexity... and so on.

  • One thing you can’t do with properties are asynchronous setters. The getter still gives, but I don’t think it’s cool, I prefer a method. An asynchronous Setter would be like this: async Task SetValueT(T value)

2 answers

26


To initial recommendation is always use the existing resource in the language until there is a reason not to use.

Functioning of the property

Understand that a property is just syntax sugar, i.e., in practice the compiler transforms a property into two methods. For example, creating a property of the type string calling for Nome, in fact internally will have a private field with a name similar to __Nome and two methods with names close to string __getNome() and void __setNome(string value).

The implementation of the first should be return __Nome; and the second __Nome = value;

Optimizing

Some people should look at this and find that calling a method and do the set or get is slower than accessing the direct field. But this may not happen because probably the JIT compiler will optimize and end up making direct access to the field, eliminating the call to the method. And if you can’t do the optimization, there must be a good reason for that.

So, initially there is no reason to create methods getNome() and setNome() manually. No advantage. It may have the disadvantage of someone not understanding why you did it.

When not using

There are some situations that a method is preferable, but not necessarily the pure and simple exchange of property for a couple of methods get and set. The question is whether something should be a simple property or something more comprehensive.

A property:

  • must be simple, should not perform complex operations;
  • should not make exceptions explicitly or implicitly through calls to other methods internally, especially the get should provide a result always;
  • may not take (probably few nanoseconds are recommended);
  • avoids extra side effects (change status of other properties);
  • is not a data conversion;
  • is usually deterministic;
  • does not return a copy of internal state unless it is a type by value;
  • does not return a very large object, in general a array.

The programmer expects a property to be as trivial as taking or putting a value into a variable. If the property code does not meet the above guidelines is likely that it is not a property even. But nothing is so black in white.

Access to large or external data

If you will create a property called Clientes that returns a list of clients obtained through a query to the database. This is not a property.

Something that is complex, makes access to external resources, can have several exceptions, is time consuming (milliseconds is an eternity) cannot be a property. In such cases, a method is more suitable because the programmer expects a method to be something more complex and that many things may occur in it.

So the solution is to create a field Clientes and a method getClientes()?

It may even be the solution. But understand that it is not a direct replacement of property, it is another operation. So it would be good to have another name and more suggestive than it does. For example ObtemTodosClientesNoDB() or ObtemClientesSelecionadosNoDB(). If you are going to save the result in a private field of the class or just return to who asked, it goes from the need.

If you’re thinking of any non-trivial logic of accessing and assigning the value, you’re probably not thinking of property.

Change of status

If a property should not change its value on its own. Often we see even the . NET missing in it. For example the property Now class DateTime does not have a stable value. Then the recommendation would be to use a method (probably DateTime.GetCurrentDateTime()) and not a property.

There are controversies whether a database field should be represented by a property. The field can be changed by other external agents running your application at that time. It is not stable. On the other hand, a field has the face of property. You do not access fields in a DB with methods, you access with the field name or attribution to this name. However, some classes represent an image of a database data in memory and not the exact record. If you think this way, you are not violating the recommendation of stability of your content. Anyway, recommendations were created to be violated when there’s a good reason for this.

Properties should not have been changeable. So it should not be complex structures, especially data collections. But there are always exceptions.

Think about the fields (state) and the methods (behavior) a class should have. Then turn your fields into properties. This is a "rule" that helps define what is what. If by chance your property requires some simple logic in get and/or in the set, then you implement.

A property is better than a public field

At least it can give more flexibility for future maintenance. But this flexibility is not always required.

Contract and abstraction

A public field cannot be replaced without breaking the "contract" of the class. The access or assignment of value in a field cannot be "intercepted" to perform something different in the process of obtaining or assigning value, let alone putting such an intervention after the field has already been made publicly available for others to use. You can’t do that without breaking the contract.

So with the property, which is usually public, you encapsulate the private field (implementation detail), hide the concrete implementation and publish only the abstraction. Even if you have nothing to do with the property, having it right from the start in creating the class allows you to change its behavior in the future without breaking any contract.

This is why only Jitter does the optimization, it is done until the last moment, the optimization is done taking into account, including, the versioning of your application.

What is valid to do in a property

Normally the most a code property has is a validation before assignment, a simple calculation before returning a result, a write to log, a cache check, etc. When you have!

Some people think that using cache in property should be discouraged because the first execution can be slow. But there is another current that thinks that all the other accesses are very fast and so the property falls like a glove. The property only reads the value stored in the cache except on the first access that can perform a more complex processing. I like this last one, because it is already very common in several classes. Seems to me a good exception.

What not to do

A property should be seen as a substitute for a public field. Not as a substitute for methods. If these methods are not doing strictly operations directly linked to a specific private field, so they should not be thought of as properties.

There’s no problem having methods getIsso() or setIsso() whether they perform operations that go beyond simply accessing and assigning values to a field.

Simplifying

Note that the most common way to declare a property is

public string Nome { get; set; }

That is, it is practically the same as declaring a public field, but it has the advantage of abstraction, that is, it allows you to add some logic in the future get and/or set. It is rare to use logic within these elements.

With the property you facilitate both source and binary compatibility. In addition you gain capability of reflection that a field doesn’t have. And it’s easier thresh a property (fields may not have breakpoint) - improved feature in Visual Studio 2015.

Counterpoint

What many people don’t realize is that very simple systems that will be used for very few things, that its maintenance will be almost non-existent and done by one person, that’s not so important. In such systems it may be better to go in the simplest solution that is to leave the public field even. Unless you know in advance that you will need some processing in access or assignment. Even if one day you have to change an access, in a simple system, changing all the places of use is very easy, even more if you are using Visual Studio and more with Resharper.

Of course, if the system complicates a little bit, it will force you to touch it for more maintenance peace of mind. So make sure the system stays simple before you direct access.

Your specific problem

getDia, getMes, getAno and isBissexto would be their properties, right? Let’s change their names a little bit. Dia, Mes, Ano and isBissexto. Ready, now it becomes more suitable. Where you keep the day calls Dia, where he keeps the month, calls Mes and p/ save year, flame Ano. Finally where you determine whether is leap, flame isBissexto.

Code style

It is the standard adopted by most programmers that boolean values always have an "Is" (or "Eh" for those who like to participate, or É for those who like accents) before the property name to make it clear that there is a binary value true or false. The property might well call just Bissexto, but a IsBissexto or EhBissexto makes it clearer that what is stored there is whether "is or is not".

Example

So let’s assume you want some code out of class that can’t set these properties, they would be implemented like this:

public byte Dia { get; private set; }
public byte Mes { get; private set; }
public byte Ano { get; private set; }
public bool IsBissexto { get; private set; }

Remember that we do not convert a method to a property, we convert a field to a property.

Correct reasoning

Your reasoning about the IsBissexto is correct. Even if there is a logic to get whether the year is leap or not, it is still a property. In fact it may be that the IsBissexto or have what we call backing field, which is a private field that holds a value. It is as if the IsBissexto is a virtual field. It can give you the result by calculating something. A simplified implementation (calculating leap is more complicated than that) would be:

public bool IsBissexto { 
    get {
        return (Ano % 4 == 0);
    }                   
}

In the proof class, really everything there seems to be property. Of course you could have, hypothetically, a method AceitarResposta() that would not only put a value on repostaAluno but also take the opportunity to update acertos and perhaps one or two more things that were necessary when an answer is accepted in the object instance. If that AceitarResposta operates in various properties, if it does more than just assign a value to a specific property, it is clearly a method, a class behavior.

Poor classes (anemic classes)

It is OK if a class has only properties. It is not so common, but there are cases like this.

Of course we don’t get into the question of class builder. In these cases it is common to have at least one builder for set the initial values of the properties when an object of this class is created. But there is another subject.

C#

In C# 6 this is easier and can even, in certain cases, dispense with the existence of a specific constructor. In C# 6 a property can have an initializer:

public Decimal Nota { get; set; } = 0.00M;

In C# 9 it is possible to let the property only be initialized:

public Decimal Nota { get; init; };

Property that does processing

The only caveat I make is whether there’s logic or not. A property may or may not have logic (conceptually it always has the implementation indicated in the second section of this text).

What the logic contained in it executes is that it determines whether it is a property of fact or should be a method. In the cases cited the existing possible logic is only something simple to give access to information, a calculation with class members. Eventually if the set is available you could implement so:

private byte mes;
public byte Mes { 
    get {
        return mes;
    }
    set {
        if (value > 0 && value <= 12) {
            mes = value;
        }
    }
}

Note that in cases where you implement a logic in set or in the get, cannot use the compact form of the property syntax. In this case you must declare a private field (normally the same name is used as the property, only starting with lowercase) and then declare the body of the method (because this set up there is a disguised method).

value is a context "variable". Inside a set there’s always that value and it is always of the same property type. It is the parameter of the set which receives the value you passed with attribution syntax.

Then use:

objeto.Mes = 3;

internally will be something like

objeto.__setMes(3);

Example of wrong use

One last example to reflect how a property can be wrong if it is trying to replace a method:

class BoxedInt {
    public int Value { set; get; };
}

which is the same as:

class BoxedInt {
    int value;
    public int Value {
        set { this.value = value; }
        get { return this.value; }
    }
}

Everything seems okay, but it’s not quite what it should be. We don’t really have a property there. In this case when you want to put a value in this class is when you are creating the class instance. Therefore the set He’s actually the builder. And when you’re picking up the value, you’re doing more than picking up a value, you should make it explicit which operation is being done which is the unpacking of the value (Unboxing), then you ask to do the Unbox. So the intention becomes more explicit:

class BoxedInt {
    int value;
    public BoxedInt(int v) { this.value = v; }
    public int Unbox() { return this.value; }
}

Methods getter and Setter

In C# it is not common to use method only to do the get and the set values. Although properties are just methods getter and Setter, do not create methods even, as occurs in other languages.

Has a question about that and there I speak that not always the property is useful.

I put in the Github for future reference.

14

The @Maniero response is already perfect, so I’ll just add a few points that I consider good practice, and make notes on the ones already mentioned:

  • estates force the get and set to stay close visually... this is very good, as it allows you to organize the code in a clear way.

  • properties may have getter and Setter with distinct visibilities, It is possible to make properties that are read-only to the outside world, but can be set internally:

    public string Nome { get; private set; }
    
  • properties should be minimalist, and in my opinion, a property should at most be used to add aspects to a private field, or serve as a shortcut.

    When I say aspect, I’m talking about cache, log, validation, but never interfere drastically with that assumption.

    private string valorCalculado;
    public string ValorCalculado
    {
        get
        {
            // note que esse ainda é uma caso muito banal para se usar cache
            if (valorCalculado == null)
                valorCalculado = "Nome => " + this.Nome + "; Idade => " + this.Idade;
            return valorCalculado;
        }
    }
    

    However, I am not in favour of using properties, even with caching, if the first call has side effects, or if they are too complex. In this case, I prefer to have another method to initialize the object, whose call is mandatory, before using the property:

    private string valorCalculado;
    
    /// <summary>
    /// Obtém o valor calculado do cache. Não esqueça de chamar 'EnsureValorCalculado'
    /// antes de usar esta propriedade.
    /// </summary>
    public string ValorCalculado
    {
        get
        {
            if (valorCalculado == null)
                throw new Exception("Chame o método 'EnsureValorCalculado' antes de usar 'ValorCalculado'.");
            return valorCalculado;
        }
    }
    
    public void EnsureValorCalculado()
    {
        // obter o valor a ser colocado em cache
    }
    

    And finally, when I say shortcut, I’m talking about getting information from nested objects, and only if it’s something very important to the object itself:

    public string Url
    {
        get { return this.Context.HttpContext.Request.Url; }
    }
    
  • just like @Maniero, to get something that requires complexity, I like to create methods instead of properties: GetComplexData, or else TryGetComplexData with a parameter out when a method may fail more than exceptionally (i.e., when failure is something common, exceptions in my view should be exceptional)... among other standards.

  • on public fields, I am not in favor, except in classes of extreme use, or in structs, in which case I’m more tolerant, but I like to keep it restricted. Already read-only static fields, I don’t see much against depending on the use. Generally use to create constants.

  • 1

    I am also in favor of small properties using LINQ, to get information from a collection... in this case the technique using cache is a good alternative.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.