Сокращения и установщики C # сокращений - PullRequest
7 голосов
/ 15 января 2012

Как сеттеры и геттеры в C # реализуют инкапсуляцию?Я не новичок, когда дело доходит до этих сеттеров и геттеров, у меня есть опыт программирования, в частности Java.в Java вы используете сеттеры и геттеры вот так

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 # реализуют инкапсуляцию в этом?Как я могу реализовать этот код C # так же, как код Java выше?Есть ли какие-либо ограничения в этом отношении?Исходя из моих наблюдений, я могу использовать это «fName» только в том случае, если оно установлено в public, а именно: «public string fName {get; set;}», но когда дело доходит до private, я не могу.но когда я установил его как приватный, я больше не могу получить к нему доступ другими способами.

Ответы [ 4 ]

11 голосов
/ 15 января 2012

Они не позволяют вам указать инкапсулирующее поведение.Они позволяют вам указать, что это свойство в общедоступном интерфейсе вашего класса, а не в поле.

Разница в том, что в Java геттеры и сеттеры - это просто методы, которые следуют определенному соглашению (getXXX, setXXX).В C # свойства являются первоклассной конструкцией (хотя они в основном являются геттерами и сеттерами за кулисами).Таким образом, C # предоставляет это как краткий способ сказать, что вы могли бы реализовать инкапсуляцию позже (например, добавить поведение к получателю или установщику), но вы не хотите разрушать потребителей вашего класса, поэтому вы объявляете их как свойства заранее.

В 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;
}

Предположим, у вас есть потребительский класс FooReader, определенный в другой сборке, которая ссылается на сборку Foo:

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; } }
}
4 голосов
/ 15 января 2012

Как вы сами сказали, версия C # - это сокращение для следующего:

private string _name;

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

(Обратите внимание, что закрытое поле недоступно, оно сгенерировано компилятором. Весь ваш доступ будет через свойство, даже из класса)

По сравнению с java, где getter / setter - просто методы, эта конструкция называется свойством в C # и является функцией компилятора.

2 голосов
/ 15 января 2012

In, C # эквивалент кода внутри вашего класса Person будет:

private String _name;

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

Начиная с C # 3, вы можете сократить это до:

public string Name { get; set; }

Это автоматически реализованное свойство , и компилятор автоматически сгенерирует тот же код инкапсуляции, что и при длительной записи. Для вас автоматически создается личное поле поддержки, а также методы get и set. Действительно, после того, как компилятор сгенерирует код IL, у вас будет поле с двумя методами get_Name и set_Name, поэтому, используя автоматически реализованное свойство, вы позволяете компилятору генерировать практически одинаковый код как у вас в вашем примере Java.

1 голос
/ 12 июня 2014

Я собираюсь немного изменить ваш вопрос, чтобы обеспечить лучшее сравнение.В Java обычно есть общедоступные методы получения и частные методы установки, при этом конструктор является инициализатором [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 вас учат, что переменные класса должны быть локальными (частными) и доступ к ним должен осуществляться только с помощью методов получения и установки.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
}

Теперь, если вы хотите добавить логику в ваш метод получения и установки, используя вышеуказанные соглашения, вам нужно будет ввести локальную частную переменную, но код в 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";
    }
}
...