C# 使用类型对象作为返回类型-错误的做法?

C# 使用类型对象作为返回类型-错误的做法?,c#,oop,methods,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类型的对象 然后我将对象强制转换回以前

我有办法

    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方法可以在整个应用程序中重用


这是一种常见的做法还是我应该避免这样做

您可以改用泛型方法,并将类型参数约束到您的
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;
}
编辑…

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

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

使用泛型可以更好地实现这一点。您可以对泛型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;
}
这里,泛型typeparam“T”实际上是由编译器通过调用该方法的方式推断出来的


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

因为您要传入实现IGrid的类的对象,所以您也可以将返回类型更改为IGrid

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

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

在上述示例中,不需要返回
grid
IGrid
实例是通过引用传递的,因此您的
projectModel
引用将随着您在
SetGrid
方法中所做的更改而更新

如果仍要返回参数,请至少返回
IGrid
,因为已知该参数是
IGrid


一般来说,在使用静态类型语言/方式编程时,请提供尽可能多的类型信息。

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

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

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

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

  • 它会导致返回类型的非特定强制转换。这是一个性能下降,这可能是不明显的。。。但是仍然没有必要,因为您是从接口强制转换的,所以即使对象与传入的参数不同,也要返回该接口

  • 返回对象会使函数的用户感到困惑。假设函数创建了一个副本并返回了一个副本。。。您仍然希望返回传入的接口,以便使用该函数的人知道“嘿,我要返回一个IGrid”,而不必自己弄清楚返回的是什么类型。你越少让你的队友想到这样的事情,对你和他们都越好


  • 这是一个非常奇怪的例子,因为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
    扩展该抽象类



    那么坚实的原则呢?具体而言,是单一责任原则。这门课首先有点像DTO用户137348

    我在这里使用的是不可靠的原则,对类的客户机隐藏实现。也就是说,客户端不必访问它正在使用的类的内部,否则就是违反了

    (SRP)只告诉类应该只有一个更改的原因,这是一个非常模糊的限制,因为更改可以像您希望的那样窄和宽

    我相信,如果参数类足够小的话,可以将一些配置逻辑放在参数类中。否则我会把它全部放在工厂类中。我建议此解决方案的原因是,
    IGrid
    似乎引用了
    PagerHelper
    SortHelper
    ,它们似乎是
    IGrid
    的突变


    所以我觉得很奇怪,你提到这个班是一个学生。纯粹意义上的DTO不应该包含除访问器(即getter方法)之外的逻辑,这使得
    ProjectModel
    本身引用了
    PagerHelper
    SortHelper
    ,我认为它们可以对其进行变异(即,它们是setter)。如果您真的想要SRP,“助手”应该在一个工厂类中,该类创建
    IGrid
    /
    ProjectModel
    实例。

    Highfive用于同时得出相同结论。如果要返回任何内容,为什么不直接返回IGrid呢?如果你把它作为一个扩展方法,我会+1:)那么固体原理呢?具体而言,是单一责任原则。首先,这门课有点像DTO。谢谢你详尽的解释!!提供了一些需要考虑的内容。感谢您的解释,但是这个方法的通用版本呢?
    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();