简体   繁体   English

为C#中的方法或构造函数提供过多的重载是不好的形式吗?

[英]Is it bad form to provide excessive overloads for a method or constructor in C#?

I am writing code for Unity, using C#. 我正在使用C#为Unity编写代码。 At present, I am dealing with a few smaller classes and structures, in effort to quickly serialise a randomly generated map. 目前,我正在处理一些较小的类和结构,以快速序列化随机生成的地图。 In doing so, I deal with a few constructors that also take some of these smaller classes and structures, as parameters. 为此,我处理了一些构造函数,这些构造函数也将这些较小的类和结构中的一些作为参数。

In the past, I would typically try to consider the plausible options when setting up my methods and constructors. 过去,在设置方法和构造函数时,我通常会尝试考虑合理的选项 While this practice has been questioned , no-one has managed to give me any plausible reason as to why I shouldn't do it in this way. 虽然这种做法已被质疑 ,没有人成功地给我任何理由似是而非,为什么我不应该做这样。


Consider the following class and structures: 考虑以下类和结构:

public class Tile
{
    public GridCoordinates position;
    public TileCode prefabID;
}

public struct GridCoordinates
{
    public int x;
    public int y;
}

public struct TileCode
{
    public int categoryID;
    public int individuaID;
}

Typically, I would cover all struct and int alternatives, when creating the constructors. 通常,在创建构造函数时,我会介绍所有structint替代方法。 Tile would look something like this: Tile看起来像这样:

public class Tile
{
    public GridCoordinates position;
    public TileCode prefabID;

    public Tile(TileCode prefabID, GridCoordinates position)
    {
        this.prefabID = new TileCode(prefabID);
        this.position = new GridCoordinates(position);
    }

    public Tile(TileCode prefabID, int xPosition, int yPosition)
    {
        this.prefabID = new TileCode(prefabID);
        position = new GridCoordinates(xPosition, yPosition);
    }

    public Tile(int typeID, int individualID, GridCoordinates position)
    {
        prefabID = new TileCode(typeID, individualID);
        this.position = new GridCoordinates(position);
    }

    public Tile(int typeID, int individualID, int xPosition, int yPosition)
    {
        prefabID = new TileCode(typeID, individualID);
        position = new GridCoordinates(xPosition, yPosition);
    }

I tend to do this for efficiency. 我倾向于这样做是为了提高效率。 It takes me an insignificant amount of excess time to write the additional constructors/methods in tandem with the first constructor/method, and I find this sometimes comes in handy when I later wish to use the constructor/method in a way I had not originally anticipated. 与第一个构造函数/方法串联编写其他构造函数/方法时,我花费了很少的时间,当我后来希望以一种本来不是我原来的方式使用构造函数/方法时,我发现这有时会派上用场预期的。

The only issue that has been raised, previously, is the potential for confusion. 以前提出的唯一问题是混乱的可能性。 I feel this is not really an issue, as my organisation and comments clearly distinguishes each variation. 我觉得这并不是真正的问题,因为我的组织和评论清楚地区分了每个变体。


Ultimately, I am concerned that there may be other issues that my teachers and peers have been unaware of. 最终,我担心我的老师和同龄人可能还没有意识到其他问题。 I am currently looking at expanding into a much larger project, and it would be much easier to curve my behavior now, than correct it later. 我目前正在考虑将其扩展到一个更大的项目,现在改变我的行为,比以后纠正它要容易得多。

What concerns do I face, if I provide excessive alternative constructors or methods for my classes? 如果我为类提供过多的替代构造函数或方法,我将面临什么问题?

  • I am not as concerned about aesthetic and standards issues, though a good answer might mention them. 我不太关心美学和标准问题,尽管可能会提到一个好的答案。 I do try to follow C# standards, but not always . 我确实尝试遵循C#标准,但并非总是如此
  • I do have concerns about the potential resource requirement this might pose, so a good answer might acknowledge any issues this may have, there. 确实担心这可能带来的潜在资源需求,因此一个好的答案可能会承认那里可能存在的任何问题。
  • As I had mentioned, I am writing for Unity. 如前所述,我正在为Unity写作。 I am aware that while most C# conventions are standard, there are a few variations, in context of running in Unity. 我知道,尽管大多数C#约定是标准的,但是在Unity中运行时,还是有一些变体。 Bonus points for addressing this, specifically, but a good answer will address using the language, in general. 专门解决此问题的加分点,但通常来说,使用该语言可以解决问题。

I see nothing wrong defining as many overloads as you see fit, as long as they are clearly documented. 只要定义清楚,就可以定义尽可能多的重载,我认为没有错。 I'm not aware of any good practice or principle recommending to the contrary. 我不知道有任何相反推荐的良好做法或原则。 A clear disadvantage is obviously the increases costs in code maintenance; 一个明显的缺点显然是代码维护成本的增加。 documentation and testing whenever you need to change something. 需要进行更改时进行文档记录和测试。

Which brings up my major gripe with the code you've posted; 这使我对您发布的代码产生了极大的抱怨; what I do find worrisome in your code and I'd never write similar were it mine is so many independent implementations. 我确实在您的代码中感到担忧,而且如果有很多独立的实现,我永远也不会写类似的东西。 If you later on decide to change the constructor logic, you'll have to change it all over the place and that will be very bug prone. 如果以后决定更改构造函数逻辑,则必须在整个位置进行更改,这很容易发生错误。 I'd refactor the code to use constructor chaining and implement all construction logic in one single overload and simply chain/delegate all other constructors to that single one. 我将重构代码以使用构造函数链接,并在单个重载中实现所有构造逻辑,然后简单地将所有其他构造函数链接/委托给该单个构造函数。

All that said, my personal opinion is that you should favor as much as possible overloads where the arguments are as "strongly typed" as possible regarding your business domain. 综上所述,我个人的观点是,对于有关您的业务领域的参数应尽可能“强类型化”,您应该尽可能支持重载。 By this I mean: 我的意思是:

public Foo(int i, int j, int k, int n) { ... }

Is horribly error prone. 容易出错。 A call to Foo(j, i, k, n) is perfectly valid and it can be very hard to locate in a big code base once the bug crops up, possibly well down the call stack. Foo(j, i, k, n)的调用是完全有效的,并且一旦出现错误,可能很难在调用堆栈中定位,就很难在大型代码库中定位。

However a signature of the type: 但是类型的签名:

public Foo(Bar bar, Blah blah)

Is a lot safer, because the type system and the compiler can help you. 安全得多,因为类型系统和编译器可以为您提供帮助。

The problem with your approach is that it is a violation of the Don't Repeat Yourself principle (also known as "DRY"). 您的方法存在的问题是,这违反了“ 不要重复自己做”的原则(也称为“ DRY”)。 Adding "convenience constructors" that pass parameters along to dependencies increase code coupling between the two modules (specifically, control coupling ), which is, generally, a practice that should be avoided. 添加将参数传递给依赖项的“便捷构造函数”会增加两个模块之间的代码耦合(特别是控制耦合 ),通常应避免这种做法。

However, there is one situation when you should prefer convenience constructors: it happens when GridCoordinates and TitleCode are considered implementation details of Title , and therefore should not be exposed. 但是,在一种情况下,您应该偏爱便捷构造函数:发生在GridCoordinatesTitleCode被视为Title实现详细信息时,因此不应该公开。 When this is the case, you should expose only the last constructor, and remove all constructors that rely on GridCoordinates and TitleCode from the public interface of your class. 在这种情况下,您应该只公开最后一个构造函数,并从类的公共接口中删除所有依赖GridCoordinatesTitleCode构造函数。

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

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