Какая декларация лучше? - PullRequest
1 голос
/ 28 апреля 2009

Я собираюсь изменить свой стиль C # в программировании (я использовал 'public static' для переменных, методы - все).

Мой вопрос:

public class WinSock
{
    public Socket sock;
    public byte[] data;
    .....
}

var data = new byte[2058];
data = WinSock.data;

или этот:

private class WinSock
{
    private Socket sock;
    private byte[] data;
    .....
    public byte[] getdata()
    {
        get {return data;}
    }
}

WinSock ws = new WinSock();
var data = new byte[2058];
data = ws.getdata();

В обоих случаях к данным и переменным носка можно обращаться из других классов.

Какое из двух объявлений лучше?

Ответы [ 9 ]

11 голосов
/ 28 апреля 2009

Как правило, обнародование полей никогда не является хорошей идеей.

Так как getdata является свойством, оно должно называться Data.

private class WinSock
{
    private Socket sock;
    private byte[] data;
    .....
    public byte[] Data
    {
        get { return data; }
    }
}

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

4 голосов
/ 28 апреля 2009

Второй ближе к тому, что обычно считается лучшим. В объектно-ориентированном программировании мы инкапсулируем переменные в классах и выставляем только столько, сколько необходимо вне класса.

Назовите ваши свойства начальной заглавной буквой и как элемент данных, а не как метод, т.е. Data вместо getdata.

public class WinSock {

    private Socket _socket;
    private byte[] _data;

    public Socket Socket {
       get { return _socket; }
    }

    public byte[] Data {
        get { return _data; }
    }

}

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

В C # 3 также имеется сокращенный синтаксис для свойств:

public class WinSock {

    public Socket Socket { get; private set; }

    public byte[] Data { get; private set; }

}
4 голосов
/ 28 апреля 2009

С чистой стороны "декларации" секунда немного лучше. Тем не менее, с точки зрения дизайна (и из того, что можно увидеть), это не хорошо. В частности, возвращение ссылки на массив, который является частным полем в классе, является большим нет-нет. Рассмотрим:

private class WinSock
{
    private Socket sock;
    private byte[] data;
    .....

    // Read at most length bytes of data to buffer starting at offset
    // and return the number of bytes read
    public int Read(byte[] buffer, int offset, int length)
    {
        // ...
    }
}

WinSock ws = new WinSock();
var data = new byte[2058];
int bytesRead = ws.Read(data, 0, data.Length);
3 голосов
/ 28 апреля 2009
  • Класс может быть только private, если он вложенный - и тогда доступ ограничен внешними классами. internal будет более распространенным (и по умолчанию для не вложенных классов)
  • Не использовать открытые поля (public Socket sock;)
  • Учитывать автоматически реализованные свойства (например, public Socket Socket {get; private set;})
  • Решите, будет ли getdata метод или свойство; -p
3 голосов
/ 28 апреля 2009

второй. Это называется «Инкапсуляция». Вы прячете и защищаете свои данные от внешнего мира.

1 голос
/ 28 апреля 2009

Как насчет:

public Socket Sock { get; private set; }
public byte[] Date { get; private set; }

Автоматически реализованные свойства - это тот путь, который вам нужен, если ваши геттеры и сеттеры не требуют никакой логики проверки. Это обеспечивает инкапсуляцию и позволяет позже при необходимости изменить реализацию на свойство, реализованное вручную, без принудительной перекомпиляции .dll, ссылающейся на вашу.

0 голосов
/ 28 апреля 2009

Несколько дополнительных очков:

  1. Если вы планируете модульное тестирование кода, использующего класс WinSock, вам следует рассмотреть возможность сделать этот класс открытым, а не внутренним, и рассмотреть вопрос о том, чтобы сделать методы виртуальными. Этот тип класса часто необходимо смоделировать или заглушить, чтобы он возвращал вызывающей стороне разные данные, чтобы можно было выполнить разные пути в коде вызывающей стороны.
  2. Вы должны рассмотреть, как будут создаваться объекты этого класса. Например, вы передадите Socket или передадите некоторые данные классу, чтобы он мог создать Socket? Ваша цель должна состоять в том, чтобы передать любые данные, необходимые для создания объекта в полезном состоянии.
  3. Вы должны подумать, как вы будете тестировать этот класс. В частности, как этот класс получит любые другие классы, которые он должен использовать для выполнения своей задачи. Для этого вы должны искать на Dependency Injection. Это начнёт вас по полезному пути.
0 голосов
/ 28 апреля 2009

Я бы также поручился за второй бит кода с той поправкой, что вы оборачиваете свои поля в свойства и правильно называете их. Таким образом, вы бы назвали свое свойство «Данные», а не «getdata».

0 голосов
/ 28 апреля 2009

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

public class WinSock
{
    private Socket sock;
    private byte[] data;

    public byte[] Data
    {
       get { return data; }
       set { data = value; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...