有没有办法编写仅由返回值变化的扩展方法?也许使用泛型? [重复]

问题描述 投票:-3回答:2

这个问题在这里已有答案:

是的,这与“方法的通用接口重载”具有很强的相似性。感谢您找到该主题。但请注意,它不是“完全重复”。

请阅读Q标记为重复后插入的文本栏 - 它表明“重复问题”的意图是在问题与现有问题完全重复时进行标记,因此不会向SO添加任何内容。正如我在下面解释的那样,为了回应三个提议的副本,这是不正确的(IMO)。而不是标记为重复,添加链接到相关问答的答案或评论以及解释连接会更有帮助。

在那种情况下,OP正在使用泛型,并且如果不仔细研究细节,就会发现错误只是因为返回类型而有所不同。在这里,OP专注于OVERLOADING,并认为答案可能是泛型(它不是)。


将此问题作为方法签名的问答重复是错误的。有人(包括我,之前)没有意识到“过载+仅通过返回的值而不同”的解决方案通过使用“out”参数来解决,很可能只会通过阅读Q&A来混淆。

考虑一下尚未理解某个主题的人的心态。相关问答之间存在差异,如果在这里给出了答案,答案可能对某人有用,这解释了其他问答的帮助,并包含了该问答的链接,以及重复的问答,这是一个问答。非常相似的线程。


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

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

如果他们已经知道解决方案是一个out参数,那么另一个问题只能帮助他人。 (该问题没有提到“扩展”或“返回”/“返回值”。)


我有很多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#的答案也很有用。)

c# vb.net generics extension-methods
2个回答
0
投票

如果你的方法只能通过返回值变化,那么如果分配结果的变量是隐式输入的,或者多个返回类型可以赋值给变量,你怎么知道你要调用哪个方法?

例如,假设您有以下三种方法:

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。但是,如果我们这样做,我们就错过了为我们的参数提供有意义的名称,以帮助其他人遵循代码。

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


-2
投票

使用显示的语法,不,因为(如上所述)方法签名不考虑返回类型。

但是,还有另一种“从方法返回值”的方法:out参数。 Out参数是签名的一部分,因此可以重载。

(注意:“通用类型”不是解决这个问题所必需的;这只是方法声明的“签名重载”。)

在Visual Basic(.NET)中,这看起来像:

<Extension()>
Public Sub ReadT(br As BinaryReader, <Out()> ByRef v2 As Vector2)
    ...
End Sub

<Extension()>
Public Sub ReadT(br As BinaryReader, <Out()> ByRef v3 As Vector3)
    ...
End Sub

因此用法变为:

    Public Sub Read(br As BinaryReader)
        br.ReadT(Position)
        br.ReadT(Normal)
        br.ReadT(TextureCoordinates)
    End Sub

很好,用法的语法类似于使用Write方法。很容易编码Read,复制/粘贴,更改声明,并用br.ReadT替换所有bw.WriteT


等效的C#:

// extension methods must be in a *static* class.
public static class ReadWriteExtensions
{
    public static void ReadT(this BinaryReader br, out Vector2 v2)
        ...

    public static void ReadT(this BinaryReader br, out Vector3 v3)
        ...
}

用法:

void Read(BinaryReader br)
{
    br.ReadT(out Position);
    br.ReadT(out Normal);
    br.ReadaT(out TextureCoordinates);
}

在C#中,读/写使用情况类似,但在“ReadT”调用中,必须在返回值的每个参数之前添加“out”。 (“WriteT”调用不会有“out”,因为参数是这些方法的输入。)

© www.soinside.com 2019 - 2024. All rights reserved.