简体   繁体   English

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

[英]Using type object as returning type - bad practice?

I have a method 我有一个方法

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

        return grid;
    }

which returns an object of type object. 返回object类型的对象。

Then I cast the object back to the previous type. 然后我将对象转换回前一个类型。

    var projectModel = new ProjectModel();

    projektyModel = (ProjectModel)SetGrid(projectModel);

The gain of this is, the method SetGrid can be reused across the app. 获得的是,方法SetGrid可以在应用程序中重用。

Is this a common practice or should I avoid doing this ? 这是一种常见做法还是应该避免这样做?

You could use a generic method instead, and constrain the type argument to your IGrid interface: 您可以使用泛型方法,并将类型参数约束到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;
}

You should still be able to call the method in exactly the same way, just without the cast. 你应该仍然能够以完全相同的方式调用方法,只是没有强制转换。 Type inferencing should be capable of automagically figuring out the required generic type argument for you: 类型推断应该能够自动为您找出所需的泛型类型参数:

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

EDIT... 编辑...

As other answers have mentioned, if your IGrid objects are reference types then you don't actually need to return anything at all from your method. 正如其他答案所提到的,如果您的IGrid对象是引用类型,那么您实际上不需要从您的方法返回任何内容。 If you pass a reference type then your method will update the original object, not a copy of it: 如果传递引用类型,那么您的方法将更新原始对象, 而不是它的副本:

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

Since you are passing in an object of a class that implements IGrid you could just as well change the return type to IGrid. 由于您传入的是实现IGrid的类的对象,因此您也可以将返回类型更改为IGrid。

Also, since it's a reference type you don't even need to return the grid again. 此外,由于它是参考类型,您甚至不需要再次返回网格。 You could just as well use this: 你也可以这样用:

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

This is better accomplished with generics. 使用泛型可以更好地完成。 You can use a constraint on the generic typeparam to preserve your type safety! 您可以在泛型类型参数上使用约束来保护类型安全!

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

and then 接着

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

Here, the generic typeparam "T" is actually inferred by the compiler by the way you call the method. 这里,泛型类型参数“T”实际上是由编译器通过调用方法的方式推断出来的。

It's worth noting that in the particular use-case you've demonstrated, returning grid is probably unnecessary, as your original variable reference will be appropriately modified after the method call. 值得注意的是,在您演示的特定用例中,返回grid可能是不必要的,因为在方法调用之后将适当地修改原始变量引用。

In the case you illustrate above there is no need to return grid . 在上面说明的情况下,不需要返回grid The IGrid instance is passed by reference, so your projectModel reference will be updated with the changes you've made in the SetGrid method. IGrid实例通过引用传递,因此您的projectModel引用将使用您在SetGrid方法中所做的更改进行更新。

If you still want to return the argument, at least return IGrid , since it is already known that the argument is an IGrid . 如果你仍然想要返回参数,至少返回IGrid ,因为已经知道参数是IGrid

In general, provide as much type information as you can when programming in a statically typed language/manner. 通常,在以静态类型语言/方式编程时提供尽可能多的类型信息。

"Is this a common practice or should I avoid doing this ?" “这是一种常见做法,还是应该避免这样做?”

This is not common practice. 这不是常见的做法。 You should avoid doing this. 你应该避免这样做。

  1. Functions that only modify the parameter passed in should not have return types. 仅修改传入的参数的函数不应具有返回类型。 If causes a bit of confusion. 如果引起一点混乱。 In the current C# you could make the modifying function an extention method for better read-ability. 在当前的C#中,您可以将修改函数作为扩展方法以获得更好的可读性。

  2. It causes an unnecisary cast of the return type. 它会导致返回类型的不必要的强制转换。 It's a performance decrease, which may not be noticable... but its still needless since you are casting from an interface, return that interface even if the object is different from the parameter passed in. 这是性能下降,这可能并不明显......但是由于您从接口进行转换,它仍然是不必要的,即使对象与传入的参数不同,也返回该接口。

  3. Returning object is confusing to users of the function. 返回对象使该功能的用户感到困惑。 Lets say the function created a copy and returned a copy... you would still want to return the interface passed in so that people using the function know "hey i'm getting an IGrid back." 让我们说这个函数创建了一个副本并返回了一个副本...你仍然希望返回传入的接口,以便使用该函数的人知道“嘿我正在回收IGrid”。 instead of having to figure out what type is being returned on thier own. 而不是必须弄清楚他们自己返回的是什么类型。 The less you make your team mates think about stuff like this the better, for you and them. 你的队友越少,你和他们就越能想到这样的事情。

This is a very weird example because SetGrid doesn't seem to do a lot of things other than setting some defaults. 这是一个非常奇怪的例子,因为除了设置一些默认值之外,SetGrid似乎没有做很多事情。 You are also letting the code perform manipulation on the object that could very well do that by itself. 您还要让代码对对象执行操作,这些操作本身就可以很好地完成。 Meaning IGrid and ProjectModel could be refactored to this: 意味着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;            
    }    
    // ...
}

Using this refactoring you only need perform the same with this: 使用此重构,您只需要执行相同的操作:

myProjectModel.setDefaults();

You could also create an abstract base class that implements IGrid that implements the setDefaults() method and let ProjectModel extend the abstract class. 您还可以创建一个实现IGrid的抽象基类 ,该IGrid实现setDefaults()方法,并让ProjectModel扩展抽象类。


what about the SOLID principles ? 那么SOLID原则呢? Concretely the Single Responsibility Principle. 具体而言是单一责任原则。 The class is in the first place something like a DTO. 该课程首先是DTO。 – user137348 - user137348

I'm exercising the Interface Segregation Principle out of the SOLID principles here, to hide the implementation from the client of the class. 我在这里使用SOLID原则来执行接口隔离原则 ,以隐藏类的客户端的实现。 Ie so the client doesn't have to access the internals of the class it is using or else it is a violation of Principle of Least Knowledge . 即,客户端不必访问它正在使用的类的内部,否则它违反了最少知识原则

Single Responsibility Principle (SRP) only tells that a class should only have one reason to change which is a very vague restriction since a change can be as narrow and broad as you want it to be. 单一责任原则 (SRP)只告诉一个类应该只有一个改变的理由,这是一个非常模糊的限制,因为改变可以像你想要的那样狭窄和宽泛。

I believe it is okay to put some configuration logic in a parameter class if it is small enough. 我相信如果它足够小,可以在参数类中放置一些配置逻辑。 Otherwise I'd put it all in a factory class. 否则我会把它全部放在工厂里。 The reason I suggest this solution is because IGrid seems to have reference to PagerHelper and SortHelper that seem to be mutators for IGrid . 我之所以提出这个解决方案是因为IGrid似乎有参考PagerHelperSortHelper这似乎是存取器IGrid

So I find it odd that you mention the class being a DTO . 所以我觉得很奇怪你提到这个类是DTO A DTO from a purist sense shouldn't have logic in it other than accessors (ie getter methods) which makes it strange that ProjectModel itself has references to PagerHelper and SortHelper which I assume can mutate it (ie they're setters). 纯粹意义上的DTO除了访问器(即getter方法)之外不应该有逻辑,这使得奇怪的是ProjectModel本身引用了PagerHelperSortHelper ,我认为它可以改变它(即它们是setter)。 If you really want SRP the "helpers" should be in a factory class that creates the IGrid / ProjectModel instance. 如果你真的想要SRP,那么“帮助者”应该在创建IGrid / ProjectModel实例的工厂类中。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM