【问题标题】:C# function uses extension function but VB equivalent does not?C# 函数使用扩展函数但 VB 等效函数不使用?
【发布时间】:2017-07-06 20:21:01
【问题描述】:

所以我在 C# 中有以下代码:

public Container ConfigureSimpleInjector(IAppBuilder app)
{
    var container = new Container();

    container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    container.RegisterPackages();  

    app.Use(async (context, next) =>
    {
        using (AsyncScopedLifestyle.BeginScope(container))
        {
            await next();
        }
    });

    container.Verify();

    return container;
}

app.Use() 定义为Owin.AppBuilderUserExtensions.Use(),如下所示:

public static IAppBuilder Use(this IAppBuilder app, Func<IOwinContext, Func<Task>, Task> handler);

VB等效如下:

Public Function ConfigureSimpleInjector(app As IAppBuilder) As Container
    Dim container = New Container()

    container.Options.DefaultScopedLifestyle = New AsyncScopedLifestyle()

    container.RegisterPackages()

    app.Use(Async Sub(context, [next])
                Using AsyncScopedLifestyle.BeginScope(container)
                    Await [next]()
                End Using
            End Sub)

    container.Verify()

    Return container
End Function

由于某种原因,在VB版本中,app.Use()没有使用现有的扩展功能,而是直接使用IAppBuilder.Use(),如下:

Function Use(middleware As Object, ParamArray args() As Object) As IAppBuilder

为什么 VB 代码不使用与 C# 相同的扩展函数,我怎样才能让它使用它?

编辑

为了清楚起见,扩展方法不是我自己的。它们来自 Owin 3rd 方库。所以没有重命名扩展方法的选项。

【问题讨论】:

  • 如果您在app.Use(Async ... 中使用Func 而不是Sub,会有所不同吗?目前该方法的签名与框架中的签名不匹配。
  • 我不相信,因为据我所知,它不应该返回一个值。我的意思是使用Function 会引发错误,因为它期待返回值。
  • 国际海事组织应该。为了使用覆盖的方法,签名必须匹配。看看definition。如果不是,编译器应该如何知道您想准确调用此方法?目前 Sub 它被视为一个参数(因此使用第一个方法定义)。您现在如何(您可以验证)在 C# 版本中,它使用 Func 参数调用该方法吗?
  • 对不起,我在写答案时把你的代码块误解为扩展方法。如果将 Owin 库编译为 DLL,那么我相信扩展方法也应该在 VB.NET 中工作,但我不确定。

标签: c# vb.net


【解决方案1】:

在C#代码中,因为next是Func,awaitreturns a task,所以没有return语句,但实际上返回了一个Task对象。

IMO VB.NET 代码返回 Task 对象,因为 lambda 被指定为 Sub(= C# 中的 Action)。

将 VB.NET 代码中的 Sub 更改为 Func 应该会调用所需的方法。

【讨论】:

  • @JunKang :然后试试这个:Async Function(context As IOwinContext, [next] As Func(Of Task)) As Task
  • 您可以尝试使用 lambda 来创建具有匹配签名的私有函数并将其作为参数传递。
  • 我能想到的最后一个建议......这个非常明确的方式怎么样:app.Use(New Func(Of IOwinContext, Func(Of Task), Task)(Async Function(context As IOwinContext, [next] As Func(Of Task)) As Task ...your code... ))
  • 感谢您的建议。仍然不起作用,但我会一直努力直到它起作用,所以我想如果我找到它,我会提出答案。
【解决方案2】:

在 VB (fiddle) 中,您可以在需要对象时传递 lambda 表达式:

Public Shared Sub Main()
    MyMethod(Function() True)    ' compiles
End Sub

Public Shared Sub MyMethod(o As Object)
End Sub

在 C# (fiddle) 中,这不起作用:

public static void Main()
{
    // Compilation error: Cannot convert lambda expression to type 'object' because it is not a delegate type.
    // You'd need to use: MyMethod(new Func<bool>(() => true));
    MyMethod(() => true);
}

public static void MyMethod(object o) { }

这可能是因为 lambda 表达式可以隐式转换为 VB 中的委托but not in C#

' Compiles
Dim d As System.Delegate = Function() True   
// Compilation error: Cannot convert lambda expression to type 'Delegate' because it is not a delegate type
System.Delegate d = () => true;

因此,在您的代码示例中,VB 会找到匹配的合适实例方法并使用它。在 C# 代码中,没有找到匹配的实例方法(因为你的 lambda 表达式不匹配object),而是使用了扩展方法。

请注意,如果找到匹配的方法,两种语言都更喜欢实例方法而不是扩展方法。这个can lead to subtle bugs 如果后面添加了匹配的实例方法。


如何解决这个问题?我建议为扩展方法和实例方法使用不同的名称——其他开发人员将来阅读你的代码会感谢你的。如果这不是一个选项,您始终可以显式调用扩展方法:

Owin.AppBuilderUserExtensions.Use(app, Async Sub(context, [next]) ...)

【讨论】:

  • 感谢您更正我的(现已删除的)答案。我认为你在这里有正确的想法。在 C# 中,lambda 表达式似乎不能隐式转换为 object。值得补充的是,Func 可隐式转换,但 lambda 表达式当然不是 Func。在您的示例中,如果您将MyMethod(() =&gt; true) 替换为MyMethod(new Func&lt;bool&gt;(() =&gt; true)),那么它将编译,并且即使扩展采用Func&lt;bool&gt; 而不是object,它也会更喜欢实例级MyMethod 而不是扩展方法.
  • @JoeFarrell:没错。我认为这是因为 lambda 可以在 VB 中隐式转换为委托,但在 C# 中不能。我在答案中添加了一个简短的示例。
  • 扩展方法来自Owin第三方库。因此,显然重命名事物不是一种选择。我将如何显式调用扩展方法?我做不到IAppBuilder.Use(...)
  • @JunKang:没错,应该是Owin.AppBuilderUserExtensions.Use(...)。现在应该在我的答案中修复。
  • @JunKang:向第三方库提交错误报告并告诉他们他们的扩展方法不能在 VB 中使用(除非显式调用它)可能是个好主意,因为它的名称与接受任意数量对象参数的实例方法冲突,因此总是优先。
猜你喜欢
  • 2019-08-27
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
  • 2019-12-15
  • 1970-01-01
相关资源
最近更新 更多