繁体   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