关于java:C#速记getter和setter

The C# Shorthand getters and setters

C中的setter和getter如何实现封装?我不是新的当谈到这些设定者和吸气剂,我有背景与编程,特别是Java。在爪哇,你使用这样的设定者和吸气剂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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中使用速记

1
2
3
public class Person {
    public string fName{ get; set;}
}

C速记getter和setter如何实现封装?如何实现C代码与上面的Java代码相同?有什么限制吗?根据我的观察,只有当"fname"设置为public时,我才能使用它,特别是"public string fname get;set;",但当它变为private时,我不能使用它。但是当我将它设置为private时,我不能再使用其他方法访问它。


它们不允许您指定封装行为。它们的作用是允许您指定这是类的公共接口中的属性,而不是字段。

这里的差别在于,在Java中,吸气剂和设置器只是遵循某种约定的方法(GETXXX,SETXXX)。在C中,属性是一流的构造(即使它们基本上是幕后的getter和setter)。因此,C提供了一种简略的方法来说明您以后可能实现封装(例如,向getter或setter添加行为),但您不想破坏类的使用者,因此您将它们声明为预先设置的属性。

在Java中:

1
2
3
4
5
6
7
public class Foo {
    private String fooName;
    public String BarName;
    public String getFooName() { return fooName; }
    public String setFooName(String fooName) { this.fooName = fooName; }

}

C中:

1
2
3
4
public class Foo {
    public String FooName { get; set; }
    public String BarName;
}

假设您在另一个引用foo程序集的程序集中定义了一个使用者类fooreader:

1
2
3
4
5
6
7
8
9
10
11
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改成这个不会破坏fooleader:

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

但是将foo更改为该值将破坏fooreader-您需要重新编译它:

1
2
3
4
5
6
7
8
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版是以下内容的简写:

1
2
3
4
5
6
7
private string _name;

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

(注意私有字段不可访问,它是由编译器生成的。您的所有访问都将通过属性进行,甚至从类内部进行)

与Java相比,在这里,GETT/SETTER是简单的方法,这种构造被称为C语言中的属性,并且是编译器特性。


在中,c您的Person类中的代码等价物为:

1
2
3
4
5
6
7
private String _name;

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

从C 3开始,可以将其浓缩为:

1
public string Name { get; set; }

这是一个自动实现的属性,编译器将自动生成与长时间编写相同的封装代码。将自动为您以及getset方法生成一个私有的支持字段。实际上,一旦编译器生成IL代码,您将拥有两种方法EDOCX1 2和EDCOX1 3的字段,因此,通过使用自动实现的属性,您可以让编译器生成与Java示例中几乎相同的代码。


我将稍微修改您的问题,以便提供更好的比较。在爪哇中,通常有公共吸引子和私有设置器,构造函数是变量的初始化器[SiC],例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Person{
    private String fName;

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

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

    String getName(){
        return fName;
    }
}

类的用户只能通过构造函数在初始化后检索值:

1
2
3
4
5
6
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中,您应该知道类变量应该是本地的(私有的),并且只应该用吸气剂和设置器访问。C本质上是相同的,但是语法和逻辑是不同的。用C重写我的示例将是:

1
2
3
4
5
6
7
8
9
10
11
12
13
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构造函数中的代码不会更改:

1
2
3
4
5
6
7
8
9
10
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.Y.如果你做一些类似的东西,虽然语法明智的工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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";
    }
}