【问题标题】:Is there some way to write ("overload") methods that vary only by returned value? [duplicate]是否有某种方法可以编写(“重载”)仅因返回值而异的方法? [复制]
【发布时间】:2018-01-24 17:11:22
【问题描述】:

--- 更新:---
TL;DR
虽然不可能有两个方法(在相同的上下文中;例如在同一个类中)只有返回类型不同,有可能以不同的方式解决问题:

“返回”out 参数中的值。

(C#) 不好:

// WON'T COMPILE
int myfunc() { ... }
double myfunc() { ... }

(C#) 好:

void myfunc(out int value) { ... }
void myfunc(out double value) { ... }

--- 原始问题 ---

是的,这与“方法的通用接口重载”非常相似。感谢您找到该线程。但是请注意,它不是“完全重复的”。

请阅读一旦 Q 被标记为重复时插入的文本栏 - 它表明“重复问题”的目的是标记问题何时是精确的现有问题的重复,因此不会对 SO 添加任何内容。正如我在下面解释的那样,针对三个提议的重复,这是不正确的(IMO)。添加答案评论链接到相关问答并解释连接会更有帮助,而不是标记为重复。

在那种情况下,OP 正在使用泛型,如果不深入研究细节就不清楚,错误是试图仅通过返回类型来区分。在这里,OP 专注于 OVERLOADING,并认为答案可能是泛型(不是)。


认为这是关于方法签名的问答的副本是错误的。有人(包括我之前)没有理解“重载+仅通过返回的值不同”的解决方案是通过使用“out”参数来解决的,可能只是通过阅读感到困惑那个问答。

考虑一个尚未理解某个主题的人的心态。 相关问答之间存在差异,它的答案可能对某人有用该问答的链接,以及一个重复问答,这是一个非常相似的线程。


我不认为这是 How to use generic method with "out" variable 的重复。

之所以不同,是因为目标不同。
是的,解决方案是一个输出参数,但目标是找到一种方法来重载方法仅通过返回的值不同
多年来,我一直认为这样做是不可能,因为“返回值不是方法签名的一部分。”
但是,我认为通过所有语言增强功能,现在这可能是可能的。 (直到今天我才意识到,有可能以不同的方式思考这个问题。我想我不是唯一一个对此感到迟钝的人。因此有这个问答。)

其他问题只有在知道解决方案是一个输出参数的人时才对他们有所帮助。 (该问题未提及“扩展”或“返回”/“返回值”。)


我有很多类似这样的 VB 读/写代码:

    Public Structure MyVertex
        Public Position As Vector3
        Public Normal As Vector3
        Public TextureCoordinates As Vector2

        Public Sub Read(br As BinaryReader)
            Position = br.ReadVector3()
            Normal = br.ReadVector3()
            TextureCoordinates = br.ReadVector2()
        End Sub

        Public Sub Write(bw As BinaryWriter)
            bw.WriteVector3(Position)
            bw.WriteVector3(Normal)
            bw.WriteVector2(TextureCoordinates)
        End Sub
    End Structure

其中读/写方法是扩展方法,例如

Public Module ReadWriteExtensions

    <Extension()>
    Public Function ReadVector2(br As BinaryReader) As Vector2
        Dim v2 As New Vector2()

        v2.X = br.ReadSingle()
        v2.Y = br.ReadSingle()

        Return v2
    End Function

    <Extension()>
    Public Function ReadVector3(br As BinaryReader) As Vector3
        ...
    End Function

    <Extension()>
    Public Sub WriteVector2(bw As BinaryWriter, v2 As Vector2)
        ...

    <Extension()>
    Public Sub WriteVector3(bw As BinaryWriter, v3 As Vector3)
        ...
End Module

我知道我可以使用参数类型的“重载”来简化 Write 方法以使其具有相同的名称。 (我使用“WriteT”来区分内置的 BinaryWriter 方法,但我可以简单地使用“Write”。):

Public Sub WriteT(bw As BinaryWriter, v2 As Vector2)
    ...

Public Sub WriteT(bw As BinaryWriter, v3 As Vector3)
    ...

因此使用变得更容易:

    Public Sub Write(bw As BinaryWriter)
        bw.WriteT(Position)
        bw.WriteT(Normal)
        bw.WriteT(TextureCoordinates)
    End Sub

但我没有这样做,因为我看不到如何执行与“读取”方法等效的操作。显而易见的尝试失败了,因为方法仅在返回类型上有所不同:

<Extension()>
Public Function ReadT(br As BinaryReader) As Vector2
    ...

<Extension()>
Public Function ReadT(br As BinaryReader) As Vector3
    ...

导致编译器错误“已声明具有相同名称或签名的成员...”。

有什么方法可以达到预期的效果吗?

(C# 的答案也很有用。)

【问题讨论】:

  • @djv - 这不是那个问题的重复,因为这里的目标完全不同:很多年我有希望我可以像编写“Write”方法一样编写类似的“Read”方法。但是我当然不能[只要我认为“返回”作为方法的返回值],因为返回值不是签名的一部分。是的,解决方案是使用“输出参数”,但这不是问题。问题是“如何重载仅因返回值不同的方法?” overload 是该问题的关键词。
  • @djv ...而且我并不是唯一一个一开始忽略这一点的人。有趣的是,核心 .NET 读取类的内置方法(例如 BinaryReader)使用了与我最初展示的相同的繁琐命名。这就是我多年前复制的风格。有趣的是他们不使用 out 参数来解决这个问题。尽管他们确实对“写”方法使用了重载!
  • 所以你提出了一个问题,并在一分钟内回答“否”并提供了一个替代解决方案,顺便说一句,这与this answer 几乎相同。如果我可以标记重复的答案,我会的。
  • 欺骗不是关于 question 是否与其他问题重复,而是关于是否存在可行的现有 answer。这就是为什么欺骗文本的措辞如下:这个问题在这里已经有了答案:如果后来/欺骗仍然存在,它就充当了一个“路标”,以汇集其他未来的变体答案(假设他们进行搜索)
  • 我发表评论只是为了澄清关于受骗的事情,而不是就帖子的细节展开新的争论(我没有研究它)。但是,这并不完全是 SO 的工作方式。一个问题 can 被快速删除,它已关闭 - 在那之前我们不能 VTD。答案只需要有一个 DV,然后那些可以 VTD 的人就可以这样做。否则,即使是接受了答案的 DV 问题也可能永远存在(IIRC - 很多与此相关的愚蠢规则)。而且,答案是关于代码而不是概念。我会冒险 大多数 问题在发布时不知道他们到底在寻找什么(XY 问题)

标签: c# vb.net


【解决方案1】:

如果您可以拥有仅因返回值而异的方法,那么如果分配结果的变量是隐式类型的,或者多个返回类型可分配给变量,您如何确定调用的是哪个方法?

例如,假设你有这三种方法:

Public Function GetResult() As Object
   Return new Object()
End Function

Public Function GetResult() As SomeClass
    Return new SomeClass()
End Function

Public Function GetResult() As SomeOtherClass
    Return new SomeOtherClass()
End Function

如果你这样做:

Dim result = whatever.GetResult()

result 将是什么 - ObjectSomeClassSomeOtherClass

即使你能做到:

Dim result as SomeClass = whatever.GetResult()

如果SomeOtherClass 继承自SomeClass 会怎样?任何一个都是有效的,那么你怎么知道返回了哪一个?

但最糟糕的是,在这些情况下,如果您可以这样做并且编译器试图推断您打算调用哪个方法,那么您可以删除一个方法,您的代码仍然可以编译,但删除该方法会导致您的代码调用不同的方法。那很糟。如果我们删除代码调用的方法,我们需要一个编译器错误。我们不希望它透明地猜测下一个最佳调用方法。

所以一个原因(我相信还有其他原因)是,如果签名只能根据返回类型而变化,那么方法的选择可能会模棱两可,难以遵循,并且可能会在没有警告的情况下更改。


另一方面,通过确保两个方法具有相同的名称可以获得什么?给事物起不同的名字是为我们的代码添加意义的绝佳机会,我们应该尽可能地这样做。事实上,在允许我们重复名称的情况下,我们通常不应该这样做。例如,我们可以决定每个方法的第一个参数应该是a,第二个应该是b,等等。编译器不会阻止我们一遍又一遍地使用a。但是如果我们这样做了,我们就会错过给我们的参数提供有意义的名称来帮助其他人遵循代码。

或者我们可以为所有类赋予相同的名称,但在不同的命名空间中。没有编译器错误。但是命名是好的,所以如果编译器强迫我们用不同的名字来消除歧义,那也很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 2021-04-15
    相关资源
    最近更新 更多