【问题标题】:How can I call C# extension methods in VB code如何在 VB 代码中调用 C# 扩展方法
【发布时间】:2010-09-17 19:15:37
【问题描述】:

我有一个类库,其中包含一些用 C# 编写的扩展方法和一个用 VB 编写的旧网站。

我想从 VB 代码中调用我的扩展方法,但它们没有出现在 intelisense 中,并且当我访问该站点时出现编译错误。

我已经获得了所有必需的 Import,因为包含在相同命名空间中的其他类在 Intelisense 中表现良好。

任何建议

编辑:更多信息可帮助一些 cmets。

我的实现是这样的

//C# code compiled as DLL
namespace x.y {
    public static class z {
        public static string q (this string s){
             return s + " " + s;
        }

    }
}

和我这样的用法

Imports x.y

'...'
Dim r as string = "greg"
Dim s as string = r.q() ' does not show in intelisense
                        ' and throws error : Compiler Error Message: BC30203: Identifier expected.

【问题讨论】:

  • 您是否在您的VB项目中添加了对c#库的引用?
  • 如果库的其余部分正常工作,我想不出任何静态方法调用不起作用的原因。如果您将其设为非扩展方法,它是否有效(只是尝试诊断问题所在)。
  • 还有一个问题 - 您确定 VB.Net 项目已更改为针对 .net 3.5 框架吗?我问是因为你提到这是一个旧网站。
  • @rjrapson 来自我的原始帖子“我已经获得了所有必需的导入,因为包含在相同命名空间中的其他类在 Intelisense 中看起来很好。” @ICR 我会试试的。 @rajrapson 是的,我更改了属性中的目标并检查了 web.config 中的所有额外节点
  • 您不需要以 .Net 3.5 为目标来使扩展方法起作用,但您确实需要使用 VS2008。如果您要部署站点的未编译版本,则服务器需要安装 .net 3.5,否则将无法正确编译。

标签: c# vb.net extension-methods class-library


【解决方案1】:

它对我有用,尽管有一些怪癖。首先,我创建了一个面向 .NET 3.5 的 C# 类库。这是项目中唯一的代码:

using System;

namespace ExtensionLibrary
{
  public static class Extensions
  {
    public static string CustomExtension(this string text)
    {
      char[] chars = text.ToCharArray();
      Array.Reverse(chars);
      return new string(chars);
    }
  }
}

然后我创建了一个面向 .NET 3.5 的 VB 控制台应用程序,并添加了对我的 C# 项目的引用。我将 Module1.vb 重命名为 Test.vb,代码如下:

Imports ExtensionLibrary

Module Test

    Sub Main()
        Console.WriteLine("Hello".CustomExtension())
    End Sub

End Module

这会编译并运行。 (我会调用 Reverse() 方法,但我不确定 VB 是否已经在某个地方神奇地具有反向能力 - 我不是 VB 专家。)

最初,我没有提供 ExtensionLibrary 作为 Intellisense 的导入。即使在构建之后,“Imports ExtensionLibrary”也是灰色的,并且灯泡提供了删除所谓冗余导入的机会。 (这样做会破坏项目。)请注意,这可能是 ReSharper 而不是 Visual Studio。

长话短说,它是可以做到的,而且应该可以正常工作。我不认为问题在于您使用的是旧版本的 VB,或者您的项目不是针对 .NET 3.5?

正如 cmets 中所述:还有一个额外的怪癖,那就是 extension methods won't be found when the compile-time type of the target is Object

【讨论】:

  • 我认为 ReSharper 可能是正确的。我没有让它变灰。
  • 因为这似乎是 VB 中缺少扩展方法的第一个谷歌结果,并且接受的答案来自伟大的 Skeet;我觉得这里应该注意一下它们是如何在 VB 中不使用类型“对象”的。花了几个小时在谷歌搜索结果中来回查找,直到我从@jdot 找到this SO answer
  • @ZexksMarquise:谢谢,将添加一个链接。
【解决方案2】:

扩展方法只是静态方法的语法糖。所以

public static string MyExtMethod(this string s)

可以在 VB.NET 和 C# 中调用

MyExtMethod("myArgument")

【讨论】:

  • 谢谢,我知道扩展方法的工作原理和方式。我的扩展在其他 C# 项目中工作正常,但是,正如我最初的问题所述,在引用相同 DLL 的 VB 项目中不会出现,也不会编译
【解决方案3】:

好的。根据错误消息,您肯定 使用最新的 VB 版本(VB 9!),或者该错误与此问题完全无关,因为如果该方法会出现另一个错误未找到:

错误 1 ​​'q' 不是 'String' 的成员。

【讨论】:

  • 很久以前我不记得实际问题了
【解决方案4】:
Imports x.y

'...'
Dim r As String = "greg"
Dim s As String = r.q() 'same as z.q(r) 

【讨论】:

    【解决方案5】:

    我想我已经encountered a similar problem:VB.Net 很乐意通过扩展方法进行编译,如果 Option Strict 关闭,则让它们在运行时进行推断。

    然而,VB.Net 似乎并不喜欢基本类型的扩展方法。你不能扩展Object,如果你这样做也无法解决:

    C#

    namespace NS
    ...
    
    public static class Utility {
    
        public static void Something(this object input) { ...
    
        public static void Something(this string input) { ...
    
    }
    
    // Works fine, resolves to 2nd method
    "test".Something();
    
    // At compile time C# converts the above to:
    Utility.Something("test");
    

    然而这在 VB.Net 中出错了:

    Option Infer On
    Option Explicit On
    Option Strict Off
    Imports NS
    ...
    
        Dim r as String = "test" 
        r.Something()
    

    编译没有错误,但在运行时失败,因为Something 不是String 的方法 - 编译器未能用对Utility.Something 的静态调用替换扩展方法的语法糖。

    问题是为什么?与 C# 不同的是,VB.Net 无法处理对 Object 的任何扩展! C# 中的有效扩展方法使 VB.Net 编译器感到困惑。

    作为一般的 VB.Net 规则,我会避免使用任何基本 .Net 类型(ObjectStringInteger 等)的扩展方法。您还必须小心 Option Infer,因为它在 Visual Studio 中默认打开,在命令行编译时默认关闭,VBCodeProvider,可能在网站中(取决于您的 web.config)。当它关闭时,VB.Net 中的所有内容都被视为Object,并且所有扩展方法都将保留到运行时(因此会失败)。

    我认为微软在向 VB.Net 添加扩展方法时确实失败了,我认为尝试(但失败)使其与 C# 保持一致是事后的想法。

    【讨论】:

    • 实际上,当他们决定将Object 设置为Option Strict Off 模式下的默认类型并使其行为与VB6 Variant 有点一致时,他们丢球的地方,而不是定义一个适当的Variant 类型,这在很大程度上与Object 同义,除了只有Variant 会有VB6 风格的行为怪癖]。许多其他问题由此而来。
    • @supercat 很可能 - 由于需要处理升级的 VB6 项目,他们在 VB.Net 的设计中遇到了更多问题。
    • 真的太糟糕了; VB.NET 仍然有一些可怕的古怪行为源于此。也许 MS 应该为会改变继承的古怪运行时行为的事情添加“Option Quirks Off”[例如。 Dim Five As Object=5 : Debug.Print("{0}",Object.ReferenceEquals(Five,Five)) 打印错误!],以及“Option Strict”的一些子选项 [恕我直言 myGraphics.DrawLine(mypen,5/2,3/4) 应该编译(画一条线到 (2.5f,0.75f) 但 Threading.Interlocked.CompareExchange("Hey", "Wow", "Foo") 不应该(通过读取-仅作为 ByRef 参数的值)]。
    【解决方案6】:

    我不知道您是否可以像在 C# 中那样使用点符号来调用它们,但我认为静态扩展方法将显示为静态函数,第一个参数作为扩展类型。所以你应该能够在 VB 中调用实际的类:

    StaticClass.ExtensionMethod(theString, arg1, ..., argN)
    

    您刚刚在 C# 中编写的位置:

    theString.ExtensionMethod(arg1, ..., argN);
    

    StaticClass 是您定义扩展方法的静态类的名称。

    【讨论】:

      【解决方案7】:

      ……还有一个用 VB 编写的旧网站。

      这里的“旧”是否暗示您在这里也使用旧版本的 VB?无论如何,由于扩展方法只是带有属性的普通静态(“Shared”)方法,因此您应该在任何情况下都可以调用它们。

      如果这是不可能的,您要么尝试在旧版本的 VB 中将它们称为“扩展样式”,要么您引用了错误版本的 C# 程序集。

      编辑:你确定你是Importing 整个 命名空间,即x.y 而不仅仅是x? VB 能够比 C# 更容易地访问嵌套命名空间,因此您可以在 VB 中使用以下代码使用命名空间 x.y 中的类。但是,要使扩展方法起作用,完整路径必须是Imported。

      Imports x
      Dim x As New y.SomeClass()
      

      【讨论】:

      • 是的,我正在导入完整的命名空间,“旧”的意思只是说这是一个我没有编写的站点,因此在 VB 中。一个随意的“旧”网站,而不是技术上的“旧”网站
      【解决方案8】:

      要检查两件事:

      1. 您的目标是 .Net 3.5
      2. 您正在引用 DLL

      某些工具可能会错误地为不支持它们的项目建议扩展方法。

      【讨论】:

        【解决方案9】:

        我遇到了同样的问题,并且可能不小心偶然发现了解决方案。如果我用过

        x.y.r.q()
        

        ,它也给我带来了同样的错误。但是如果我导入 x.y,它就起作用了,所以:

        using x.y;
        ...
        r.q()
        

        很好。

        所以显然你必须在声明中导入它才能使其工作。

        【讨论】:

          【解决方案10】:

          这是很久以前的事了,我真的不知道我是如何解决的,但不用说,这是用户错误。我可能重新启动了我的计算机,然后它就消失了。

          【讨论】:

            猜你喜欢
            • 2019-05-23
            • 1970-01-01
            • 1970-01-01
            • 2022-06-10
            • 1970-01-01
            • 1970-01-01
            • 2017-09-27
            • 1970-01-01
            • 2020-09-01
            相关资源
            最近更新 更多