Javaer tries to summarize how to write properties in C #

Introduction

The first programming language I learned was Java, but I didn't really understand the concept and writing of C # properties, so I'd like to organize it.

Who is the target of this article

--A person who understands the story of encapsulation in the explanation that is often found at the beginning of object-oriented programming. --People who have learned Java all the way and want to learn C # from now on. ――People who want to take a quick look at how to write properties in C #.

Comparison of writing style

Premise

Consider the ** Human class **, which is common in object-oriented explanations. Suppose the Human class has the following fields and visibility:

――Nickname …… You can easily change your nickname. There are no restrictions and you can freely retrieve and rewrite. --realname …… The real name cannot be changed so easily. So I can take it out, but I can't rewrite it. ――Age …… Age can read mackerel, so I will rewrite it this time. However, since it is an age, it must be 0 years old or older.

To achieve this requirement, the class should look like this:

--nickname: I have both getters and setters. --realname: Only have getters. --age: Have getters and conditional setters.

In addition, this time we will also define a constructor that can set that field at the same time as instantiation.

Java In Java, it's a lot to write, but it's simple to do. Fields that should be honestly defined are defined as private variables, and getters / setters are defined as just public methods. If you want to put a limit, write the logic in the method. If you don't want to be accessed in the first place, all you have to do is write a method. Also, the constructor takes arguments in turn and sets them in its own fields.

public class Main {
    public static void main(String[] args) throws Exception {
        Human konan = new Human("Shinichi Kudo", "But, Kudo", 17);

        //You can freely retrieve your nickname, real name, and age.
        System.out.println(konan.getNickname()); // ->But, Kudo
        System.out.println(konan.getRealname()); // ->Shinichi Kudo
        System.out.println(konan.getAge()); // -> 17
        
        //Nickname and age can be rewritten
        konan.setNickname("Conan Edogawa");
        konan.setAge(7);
        System.out.println(konan.getNickname()); // ->Conan Edogawa
        System.out.println(konan.getAge()); // -> 7
        
        //However, even if you enter a strange age, it will be ignored
        konan.setAge(-10000);
        System.out.println(konan.getAge()); // ->Remains 7
        
        //You cannot change your real name.
        // konan.setRealname("Conan Edogawa"); // ->I get angry because there is no such method.
        
        //Then Conan, what's your real name?
        System.out.println(konan.getRealname()); // ->Shinichi Kudo. Ah ... after all.
    }
}

class Human{
    private String realname;
    private String nickname;
    private int age;
    
    public Human(String realname, String nickname, int age){
        this.realname = realname;
        this.nickname = nickname;
        if (age >= 0){
            this.age = age;
        }
    }
    
    public String getRealname(){
        return realname;
    }
    
    public String getNickname(){
        return nickname;
    }
    
    public void setNickname(String nickname){
        this.nickname = nickname;
    }
    
    public int getAge(){
        return age;
    }
    
    public void setAge(int age){
        if (age >= 0){
            this.age = age;
        }
    }
}

There is a lot of code in the Human class. This time, I have set conditions and restrictions, so I don't feel so unpleasant, but if virtually all fields are accessible and all-you-can-eat classes, I feel barren. In some cases, the library called Lombok can be written a little more neatly, and in other cases, the getter / setter method is automatically generated by using the function of the IDE, but I will give it to another person.

Therefore, it seems that modern languages often implement a special way of writing their own fields (although they are also called attributes) getters / setters. C # is one of them.

C# In C #, you use a feature called properties to rewrite and retrieve fields from the outside. It looks as if you are rewriting the field directly. However, since it is actually via something like a getter / setter method, write this in ** Pascal case ** (in C #, the method name is Pascal case). When you use a property, it doesn't feel like you're going through a method, it feels like you're assigning it directly or referencing it directly.

using System;

public class Program
{
    public static void Main()
    {
        Human konan = new Human("Shinichi Kudo","But, Kudo",17);
        
        //You can freely retrieve your nickname, real name, and age.
        Console.WriteLine(konan.Nickname); // ->But, Kudo
        Console.WriteLine(konan.Realname); // ->Shinichi Kudo
        Console.WriteLine(konan.Age); // -> 17
        
        //You can rewrite your nickname and age.
        konan.Nickname = "Conan Edogawa";
        konan.Age = 7;
        Console.WriteLine(konan.Nickname); // ->Conan Edogawa
        Console.WriteLine(konan.Age); // ->7
        
        //However, even if you enter a strange age, it will be ignored
        konan.Age = -10000;
        Console.WriteLine(konan.Age); // ->Remains 7

        //You can't change your real name
        // konan.Realname = "Conan Edogawa"; //Its property is Read-Get angry with Only
        
        //Then Conan, what's your real name?
        Console.WriteLine(konan.Realname); // ->Shinichi Kudo. Ah ... after all.
    }
}

class Human
{
    public string Realname{ get; }
    public string Nickname{ get; set; }
    private int age;
    public int Age
    {
        get
        {
            return this.age;
        }
        set{
            if (value >= 0)
            { 
                this.age = value;
            }
        }
    }
    
    public Human(string realname, string nickname, int age)
    {
        this.Realname = realname;
        this.Nickname = nickname;
        if (age >= 0)
        {
            this.Age = age;
        }
    }
}

If you want to use a property that can be read or written, just write {get; set;} after the property name. If you want to use the read-only property, set it to {get;} [^ 1]. If you want to return or set after performing some processing internally when setting or getting, prepare a separate field (camel case because this is an ordinary variable) and after the property declaration Write as follows.

[^ 1]: ~~ Actually, the write-only property doesn't seem to be supported in C #. In this case, it will be implemented as a setter method separately. ~~ By using private get, you can use write-only properties (see postscript).

{
    get
    {
        //Something processing
return The result of processing;
    }
    set
    {
        //Something processed using value
        this.field=Result of processing;
    }
}

At this time, inside the setter, the received value is automatically received as an argument named value.

In addition, since some properties are read-only this time, the constructor looks like Java, but if all properties have write permission, you do not have to prepare a constructor. You can write something like this: It's very clean.

Human konan = new Human(){ Realname = "Shinichi Kudo", Nickname = "But, Kudo", Age = 17 };

in conclusion

There are many talks about the pros and cons of getters / setters, but there are still some things that cannot be avoided when talking about object-oriented encapsulation. Since I came from Java, I understand that objects only have variables and methods. Although it was easy to understand, I had the impression that it was redundant and troublesome.

When I first saw the C # code, I didn't even know the function of properties, so why is this guy writing variables in the Pascal case? I thought, but when I looked it up, I was impressed that it could be written so concisely. However, on the other hand, if logic is included in getter / setter, it will be slightly delayed and it will be difficult to see, and since the writing style around this is evolving with each version upgrade of C #, while investigating I got the impression that it was rather confusing because a lot of information such as "I can write like this" and "I used to write like this" came out and I was confused.

This article is also a summary for myself. We hope this article has helped you improve your C # life.

Postscript (2019/3/29)

Default value

I forgot to write it in the above article, but you can give initial values to C # properties. For example, if you want to give a newborn Human object the name "anonymous", you can write: without having to prepare a field to initialize it or define a constructor:

string name{ get; set; } = "Anonymous";

This alone is nice, but it is useful when you want to have an object of some class as a property in the class, for example.

class Human{
    public List<string> Tools{ get; set; } = new List<string>();
}

That way, you can manipulate this property suddenly from outside an object of this class.

var konan = new Human();
konan.Tools.Add("Bow tie type voice changer");
konan.Tools.Add("Kick enhancement shoes");
konan.Tools.Add("Watch type tranquilizer gun"); 

If you try to do this without initializing the property, you will get a NullReferenceException. To avoid that, you have to new outside the class and then stick.

(Thx: C # er from the same company)

write-only property

In the first article, I wrote that the write-only property cannot be used, but in reality it seems that it can be used by making it a private get property. You won't be able to read your properties even internally.

Therefore,

public string Secret { set; }

Can not be written, but

public string Secret { private get; set; }

Can be written as.

var konan = new Human();
konan.Secret = "In fact, Shinichi";
// Console.WriteLine(konan.Secret); ←Write-Get angry with Only

(Thx: @muniel)

uint type

This time I wrote it on the premise that some processing is done at the setter, so I used the int type, but there seems to be a type called uint type (Unsigned Int) called an unsigned integer. The int type handles -2147483648 to 2147483647, while the uint type handles 0 to 4294967295.

However, since the uint type basically cannot handle negative numbers, for example, 10-20 does not become -10, but 4294967286 (because of bit operation, it turns around and rushes into the larger one). It can be a hotbed of bugs due to unexpected behavior. Basically, it seems that uint type should not be used for values that can be arithmetically targeted.

However, if you really want to create a Human object, setting age to a set / getable property will update the age every year, so you probably have a birthday as a property inside, and the age is based on that. It seems good to make it a get-only property that calculates and returns a value to. (Thx: @ Tonbo0710, @ tak458, @ Zuishin)

You can also use setter in the constructor

public Human(string realname, string nickname, int age)
{
    this.Realname = realname;
    this.Nickname = nickname;
    if (age >= 0)
    {
        this.Age = age;
    }
}

In the above article, the if statement is used to prevent strange values from being inserted even in the constructor, but if you think about it carefully, you set the value via your own property here, and in that setter Since it is judged by, this should be written as follows [^ 2]. Furthermore, the property and the received variable name do not conflict in the Pascal case and camel case, so this may or may not be present.

public Human(string realname, string nickname, int age)
{
    this.Realname = realname;
    this.Nickname = nickname;
    this.Age = age;
}

(Thx: Yamada)

[^ 2]: It seems that you can set from the outside only in the constructor without writing private set.

Recommended Posts

Javaer tries to summarize how to write properties in C #
[Rails] How to write in Japanese
[JavaFX] How to write Eclipse permissions in build.gradle
JUnit 5: How to write test cases in enum
How to write Java String # getBytes in Kotlin?
Notes on how to write comments in English
How to write Rails
How to write dockerfile
How to write docker-compose
How to write Mockito
How to write migrationfile
[Ruby on Rails] How to write enum in Japanese
How to write a date comparison search in Rails
How to write an external reference key in FactoryBot
How to write a core mod in Minecraft Forge 1.15.2
Offline real-time how to write Implementation example of the problem in E05 (ruby, C11)
How to write good code
Bit Tetris (how to write)
How to write java comments
[Refactoring] How to write routing
Great poor (how to write)
[Note] How to write Dockerfile/docker-compose.yml
How to write Junit 5 organized
How to write Rails validation
How to write Rails seed
[Ruby] How to write blocks
How to write Rails routing
[Rails5] japanMap link How to write parameters in js.erb file
[Rails] How to write user_id (foreign key) in strong parameter
How to use Lombok in Spring
How to find May'n in XPath
How to hide scrollbars in WebView
How to run JUnit in Eclipse
How to iterate infinitely in Ruby
Studying Java # 6 (How to write blocks)
Read Java properties file in C #
How to run Ant in Gradle
How to master programming in 3 months
How to learn JAVA in 7 days
How to get parameters in Spark
Offline real-time how to write F03 ruby and C implementation example
Baseball ball count (how to write)
How to install Bootstrap in Ruby
How to write ruby if in one line Summary by beginner
How to write a ternary operator
How to write when you want to handle "array of C language strings" like argv [] in Ruby-FFI
How to use InjectorHolder in OpenAM
Rails on Tiles (how to write)
[Rails] How to write exception handling?
How to write Java variable declaration
How to introduce jQuery in Rails 6
How to use classes in Java?
How to name variables in Java
How to set Lombok in Eclipse
Y-shaped road tour (how to write)
How to write easy-to-understand code [Summary 3]
[RSpec] How to write test code
How to write the view when Vue is introduced in Rails?
How to concatenate strings in java
How to install Swiper in Rails
[swift5] How to specify color in hexadecimal