首页 文章

C#速记吸气剂和二传手

提问于
浏览
7

C#中的Setter和Getters如何实现封装?对于这些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;}”,但是当涉及到private时我不能 . 但是当我将它设置为私有时,我无法再以其他方式访问它 .

4 回答

  • 4

    它们不允许您指定封装行为 . 他们所做的是允许您指定这是您的类的公共接口中的属性,而不是字段 .

    这里的区别在于,在Java中,getter和setter只是遵循特定约定的方法(getXXX,setXXX) . 在C#中,属性是一流的构造(即使它们基本上是幕后的getter和setter) . 因此,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更改为此 doesn't break FooReader:

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

    但是改变Foo到这个 WILL break 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; } }
    }
    
  • 2

    正如您自己所说,C#版本是以下的简写:

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

    (注意私有字段是不可访问的,它是编译器生成的 . 所有访问都将通过属性进行,即使是在类内部)

    与java相比,getter / setter只是方法,这个结构在C#中称为属性,是一个编译器特性 .

  • 11

    在,C#中,Person类中的代码相当于:

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

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

    public string Name { get; set; }
    

    这是一个automatically implemented property,编译器将自动生成相同的封装代码,如果您要将其写出来的话 . 将自动为您生成私有支持字段,以及 getset 方法 . 真的,一旦编译器生成了IL代码,你将拥有一个包含两个方法的字段, get_Nameset_Name ,因此通过使用自动实现的属性,你可以让编译器生成几乎与你的代码相同的代码 . 你的java例子 .

  • 1

    我将稍微修改您的问题以提供更好的比较 . 在Java中,您通常使用公共getter和私有setter,构造函数是变量的初始值[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";
        }
    }
    

相关问题