Использование типа объекта в качестве возвращаемого типа - плохая практика? - PullRequest
4 голосов
/ 05 февраля 2010

У меня есть метод

    private object SetGrid(IGrid grid)
    {
        grid.PagerHelper.SetPage(1, 10);
        grid.SortHelper.SetSort(SortOperator.Ascending);
        grid.PagerHelper.RecordsPerPage = 10;

        return grid;
    }

, который возвращает объект типа object.

Затем я возвращаю объект к предыдущему типу.

    var projectModel = new ProjectModel();

    projektyModel = (ProjectModel)SetGrid(projectModel);

Преимущество заключается в том, что метод SetGrid можно повторно использовать в приложении.

Это обычная практика или мне следует избегать этого?

Ответы [ 7 ]

13 голосов
/ 05 февраля 2010

Вместо этого вы можете использовать универсальный метод и ограничить аргумент типа вашим IGrid интерфейсом:

private T SetGrid<T>(T grid) where T : IGrid
{
    grid.PagerHelper.SetPage(1, 10);
    grid.SortHelper.SetSort(SortOperator.Ascending);
    grid.PagerHelper.RecordsPerPage = 10;

    return grid;
}

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

var projectModel = new ProjectModel();
projektyModel = SetGrid(projectModel);

EDIT ...

Как уже упоминалось в других ответах, если ваши IGrid объекты являются ссылочными типами, вам вообще не нужно ничего возвращать из вашего метода. Если вы передадите ссылочный тип, тогда ваш метод обновит исходный объект, , а не его копию:

var projectModel = new ProjectModel();  // assume that ProjectModel is a ref type
projektyModel = SetGrid(projectModel);
bool sameObject = object.ReferenceEquals(projectModel, projektyModel);  // true
5 голосов
/ 05 февраля 2010

Поскольку вы передаете объект класса, который реализует IGrid, вы также можете изменить тип возвращаемого значения на IGrid.

Кроме того, поскольку это ссылочный тип, вам даже не нужно возвращать сетку снова. Вы также можете использовать это:

var projectModel = new ProjectModel();
SetGrid(projectModel);
2 голосов
/ 05 февраля 2010

«Это обычная практика или мне следует избегать этого?»

Это не обычная практика. Вы должны избегать этого.

  1. Функции, которые только изменяют переданный параметр, не должны иметь возвращаемых типов. Если вызывает немного путаницы. В текущем C # вы можете сделать функцию модификации методом расширения для лучшей читаемости.

  2. Это вызывает ненужное приведение типа возврата. Это снижение производительности, которое может быть незаметным ... но все равно не нужно, так как вы выполняете приведение из интерфейса, возвращайте этот интерфейс, даже если объект отличается от переданного параметра.

  3. Возвращаемый объект сбивает с толку пользователей функции. Допустим, функция создала копию и вернула копию ... вы все равно хотите вернуть переданный интерфейс, чтобы люди, использующие функцию, знали: «Эй, я получаю IGrid обратно» вместо того, чтобы выяснить, какой тип возвращается самостоятельно. Чем меньше вы заставляете своих товарищей по команде думать о подобных вещах, тем лучше для вас и для них.

2 голосов
/ 05 февраля 2010

В случае, который вы иллюстрируете выше, нет необходимости возвращать grid. Экземпляр IGrid передается по ссылке, поэтому ваша ссылка projectModel будет обновлена ​​с учетом изменений, внесенных вами в метод SetGrid.

Если вы все еще хотите вернуть аргумент, по крайней мере, верните IGrid, поскольку уже известно, что аргумент является IGrid.

В общем, предоставьте как можно больше информации о типах при программировании на языке / типе со статической типизацией.

2 голосов
/ 05 февраля 2010

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

private T SetGrid<T>(T grid) where T : IGrid
{
    grid.PagerHelper.SetPage(1, 10);
    grid.SortHelper.SetSort(SortOperator.Ascending);
    grid.PagerHelper.RecordsPerPage = 10;

    return grid;
}

, а затем

var projectModel = new ProjectModel();
projectModel = SetGrid(projectModel);

Здесь обобщенный typeparam "T" фактически выводится компиляторомкак вы вызываете метод.

Стоит отметить, что в конкретном прецеденте, который вы продемонстрировали, возвращать grid, вероятно, не нужно, поскольку исходная ссылка на переменную будет соответствующим образом изменена после вызова метода.

1 голос
/ 05 февраля 2010

Это очень странный пример, потому что SetGrid, похоже, не делает ничего, кроме установки некоторых значений по умолчанию. Вы также позволяете коду выполнять манипуляции с объектом, который вполне может сделать это сам по себе. Значение IGrid и ProjectModel может быть изменено следующим образом:

public interface IGrid {
    // ...
    public void setDefaults();
    // ...
}

public class ProjectModel : IGrid {
    // ...
    public void setDefaults() {
        PagerHelper.SetPage(1, 10);
        SortHelper.SetSort(SortOperator.Ascending);
        PagerHelper.RecordsPerPage = 10;            
    }    
    // ...
}

При использовании этого рефакторинга вам нужно всего лишь выполнить то же самое с:

myProjectModel.setDefaults();

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


как насчет принципов SOLID? Конкретно Принцип Единой Ответственности. Во-первых, класс - это что-то вроде DTO. - user137348

Я применяю принцип разделения интерфейса из принципов SOLID, чтобы скрыть реализацию от клиента класса. То есть таким образом, клиент не должен иметь доступ к внутренним компонентам класса, который он использует, иначе это нарушение Принцип наименьшего знания .

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

Полагаю, можно добавить некоторую логику конфигурации в класс параметров, если он достаточно мал. В противном случае я бы поставил все это на фабричный класс. Причина, по которой я предлагаю это решение, заключается в том, что IGrid, кажется, имеет ссылку на PagerHelper и SortHelper, которые кажутся мутаторами для IGrid.

Поэтому я нахожу странным, что вы упомянули, что класс DTO . У DTO с точки зрения пуристов не должно быть логики, кроме аксессоров (то есть методов получения), что делает странным то, что сам по себе ProjectModel имеет ссылки на PagerHelper и SortHelper, которые, как я полагаю, могут его мутировать (т.е. они ' сеттеры). Если вы действительно хотите SRP, «помощники» должны быть в фабричном классе, который создает экземпляр IGrid / ProjectModel.

0 голосов
/ 05 февраля 2010

Ваша сетка является IGrid, почему бы не вернуть IGrid?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...