簡體   English   中英

C#速記獲取器和設置器

[英]The C# Shorthand getters and setters

C#中的Setter和Getter如何實現封裝? 我對這些setter和getter並不陌生,我有編程方面的背景,尤其是java。 在Java中,您可以像這樣使用setter和getter

public class Person {
    private String fName;

    public void setName(String someName) {
        fName = someName;
    }

    public String getName() {
        return fName;
    }
}

public class Test {

    public static void main(String[] args) {
        Person p = new Person();

        p.setName("Bob");
        System.out.println(p.getName());
    }
}

在C#中使用速記

public class Person {
    public string fName{ get; set;}
}

C#速記getter和setter如何在此上實現封裝? 如何實現與上述Java代碼相同的C#代碼? 有什么限制嗎? 根據我的觀察,我只能將“ fName”設置為public才能使用,特別是“ public string fName {get; set;}”,但是在私有方面我不能使用。 但是當我將其設置為私有時,我將無法再通過其他方法訪問它。

它們不允許您指定封裝行為。 它們的作用是允許您在班級的公共界面(而不是字段)中指定這是一個Property。

此處的區別在於,在Java中,getter和setter只是遵循某種約定(getXXX,setXXX)的方法。 在C#中,屬性是一流的構造(即使它們基本上是幕后的獲取器和設置器)。 因此,C#提供了這些方法,以一種簡短的方式表示您稍后可以實現封裝(例如,將行為添加到getter或setter中),但是您不想破壞類的使用者,因此您將它們聲明為屬性。

在Java中:

public class Foo {
    private String fooName;
    public String BarName;
    public String getFooName() { return fooName; }
    public String setFooName(String fooName) { this.fooName = fooName; }

}

在C#中:

public class Foo {
    public String FooName { get; set; }
    public String BarName;
}

假設您在另一個引用Foo程序集的程序集中定義了消費者類FooReader:

public class FooReader {
    public String ReadFoo(Foo foo) {
        // This returns the Foo **property**
        return foo.FooName;
    }

    public String ReadBar(Foo foo) {
        // This returns the Bar **field**
        return foo.BarName;
    }
}

現在,將Foo更改為此不會破壞FooReader:

public class Foo {
    private String _fooName;
    public String FooName { get { return _fooName.ToUpper(); } set { _fooName = value; } }
    public String BarName;
}

但是將Foo更改為此破壞FooReader,您需要重新編譯它:

public class Foo {
    private String _fooName;
    private String _barName;
    public String FooName { get { return _fooName.ToUpper(); } set { _fooName = value; } }

    // This breaks FooReader because you changed a field to a property
    public String BarName { get { return _barName.ToUpper(); } set { _barName = value; } }
}

就像您自己說的那樣,C#版本是以下各項的簡寫:

private string _name;

public Name
{
   get { return _name; }
   set { _name = value; }
}

(請注意,私有字段不可訪問,它是由編譯器生成的。所有訪問都將通過屬性進行,即使是在類內部也是如此)

與java相比,getter / setter只是方法,該構造在C#中稱為屬性,並且是編譯器功能。

在C#中,Person類中的代碼等效於:

private String _name;

public string Name 
{
    get { return _name; }
    set { _name = value; }
}

從C#3開始,您可以將其壓縮為:

public string Name { get; set; }

這是一個自動實現的屬性 ,編譯器將自動生成與長時間編寫時相同的封裝代碼。 會自動為您生成一個私有后備字段以及getset方法。 確實,一旦編譯器生成了IL代碼,您將擁有一個帶有兩個方法的字段,即get_Nameset_Name ,因此,通過使用auto-implemented屬性,您可以讓編譯器生成與您使用的幾乎相同的代碼。您的Java示例。

我將略微修改您的問題,以提供更好的比較。 在Java中,通常有公共的getter和private的setter,而構造函數是變量的initializor [sic],例如:

public class Person{
    private String fName;

    public Person (String name) {
        setName(name);
    }

    private void setName(String someName){
        fName = someName;
    }

    String getName(){
        return fName;
    }
}

對於該類的用戶,只能在初始化之后通過構造函數來檢索值:

public class Example {
    Person person = new Person("Fred");
    System.out.println(person.getName()); // Allowed
    System.out.println(person.fName); // Not allowed because fName is a local class variable
    person.setName("Aaron"); // Not allowed because setName() is a local class method
}

現在,這是C#就會變得更加復雜,因為不是使用Person.getName只需使用變量本身,但是這個變量仍然可以被封裝。 在Java中,我們被告知類變量應該是局部(私有)變量,並且只能使用getter和setter進行訪問。 C#本質上是相同的,但是語法和邏輯是不同的。 用C#重寫我的示例將是:

public class Person {
    public String fName {get; private set;}

    public Person(String name) {
        this.fName = name;
    }
}

public class Example {
    Person person = new Person("Fred");
    Console.WriteLine(person.fName); // This is allowed 
    person.fName = "Tony"; // Not allowed because setter is private
}

現在,如果您想使用上述約定將邏輯添加到getter和setter中,則需要引入一個局部私有變量,但是Example和Person構造函數中的代碼不會改變:

class Person {
    private String _fName;
    public String fName {
        get { return _fName + ".addedText"; }
        private set { _fName = value.ToLower(); }
    }
    public Person(String fName) {
        this.fName = fName;
    }
}

現在,這是否比Java更好還是更壞尚有待商,,但據我所知,如果您執行以下操作,則在C#中代碼將不合時宜,盡管在語法上會起作用:

class Person2 {
    private String fName;

    public Person2(string fName) {
        setFname(fName);
    }

    private void setFname(String fName) {
        this.fName = fName.ToLower();
    }

    public String getFname() {
        return this.fName+ ".addedText";
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM