使用类型对象作为返回类型 - 不好的做法?

时间:2010-02-05 09:34:31

标签: c# oop methods

我有一个方法

    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 个答案:

答案 0 :(得分:13)

您可以使用通用方法,并将类型参数约束到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);

修改...

正如其他答案所提到的,如果您的IGrid对象是引用类型,那么您实际上不需要从您的方法返回任何内容。如果您传递引用类型,那么您的方法将更新原始对象,它的副本:

var projectModel = new ProjectModel();  // assume that ProjectModel is a ref type
projektyModel = SetGrid(projectModel);
bool sameObject = object.ReferenceEquals(projectModel, projektyModel);  // true

答案 1 :(得分:5)

由于您传入的是实现IGrid的类的对象,因此您也可以将返回类型更改为IGrid。

此外,由于它是参考类型,您甚至不需要再次返回网格。你也可以这样用:

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

答案 2 :(得分:2)

使用泛型可以更好地完成。您可以在泛型类型参数上使用约束来保护类型安全!

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);

这里,泛型类型参数“T”实际上是编译器通过调用方法的方式推断的。

值得注意的是,在您演示的特定用例中,返回grid可能是不必要的,因为在方法调用之后将适当修改原始变量引用。

答案 3 :(得分:2)

如果您在上面说明,则无需返回gridIGrid实例是通过引用传递的,因此您的projectModel引用将使用您在SetGrid方法中所做的更改进行更新。

如果你仍然想要返回参数,至少返回IGrid,因为已经知道参数是IGrid

通常,在以静态类型语言/方式编程时提供尽可能多的类型信息。

答案 4 :(得分:2)

“这是一种常见做法,还是应该避免这样做?”

这不常见。你应该避免这样做。

  1. 仅修改传入的参数的函数不应具有返回类型。如果引起一点混乱。在当前的C#中,您可以将修改功能作为一种扩展方法,以获得更好的可读性。

  2. 它会导致返回类型的不必要的强制转换。这是性能降低,这可能并不明显......但是由于您从接口进行转换,它仍然是不必要的,即使该对象与传入的参数不同,也返回该接口。

  3. 返回对象使该功能的用户感到困惑。让我们说这个函数创建了一个副本并返回了一个副本...你仍然希望返回传入的接口,以便使用该函数的人知道“嘿我正在回收IGrid”。而不是必须弄清楚他们自己返回的是什么类型。你的队友对你和他们的评价越少越好。

答案 5 :(得分:1)

这是一个非常奇怪的例子,因为除了设置一些默认值之外,SetGrid似乎没有做很多事情。您还要让代码对对象执行操作,这些操作本身就可以很好地完成。意义IGridProjectModel可以重构为:

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原则中的Interface Segregation Principle来隐藏类的客户端的实现。即所以客户端不必访问它正在使用的类的内部,否则它违反了Principle of Least Knowledge

Single Responsibility Principle(SRP)只告诉一个类应该有一个改变的理由,这是一个非常模糊的限制因为更改可以像你想要的那样狭窄和广泛是

我相信如果它足够小,可以在参数类中放置一些配置逻辑。否则我会把它全部放在工厂里。我建议使用此解决方案的原因是因为IGrid似乎引用PagerHelperSortHelper似乎是IGrid的变异器。

所以我觉得很奇怪你提到这个班级是DTO。纯粹意义上的DTO除了访问器(即getter方法)之外不应该有逻辑,这使得ProjectModel本身引用PagerHelperSortHelper这是我很奇怪的改变它(即他们是设定者)。如果您真的想要SRP,那么“帮助者”应该在工厂类中创建IGrid / ProjectModel实例。

答案 6 :(得分:0)

您的网格是IGrid,为什么不返回IGrid?